├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── colors.xml │ │ │ │ └── styles.xml │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── bye.png │ │ │ │ ├── go_on.png │ │ │ │ ├── thank_you.png │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── iv_100x100.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── layout │ │ │ │ └── activity_main.xml │ │ │ ├── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ │ └── drawable │ │ │ │ └── ic_launcher_background.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── toly1994 │ │ │ │ └── splitebitmap │ │ │ │ ├── MainActivity.java │ │ │ │ ├── Ball.java │ │ │ │ ├── BitmapTXTSplitView.java │ │ │ │ └── BitmapSplitView.java │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── toly1994 │ │ │ └── splitebitmap │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── com │ │ └── toly1994 │ │ └── splitebitmap │ │ └── ExampleInstrumentedTest.java ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .idea ├── encodings.xml ├── vcs.xml ├── runConfigurations.xml ├── gradle.xml ├── codeStyles │ └── Project.xml └── misc.xml ├── .gitignore ├── gradle.properties ├── gradlew.bat ├── gradlew └── README.md /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | SpliteBitmap 3 | 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/SpliteBitmap/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/bye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/SpliteBitmap/HEAD/app/src/main/res/mipmap-xhdpi/bye.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/go_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/SpliteBitmap/HEAD/app/src/main/res/mipmap-xhdpi/go_on.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/SpliteBitmap/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/SpliteBitmap/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/thank_you.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/SpliteBitmap/HEAD/app/src/main/res/mipmap-xhdpi/thank_you.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/SpliteBitmap/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/SpliteBitmap/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/iv_100x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/SpliteBitmap/HEAD/app/src/main/res/mipmap-xxhdpi/iv_100x100.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/SpliteBitmap/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/SpliteBitmap/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/SpliteBitmap/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/SpliteBitmap/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/SpliteBitmap/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toly1994328/SpliteBitmap/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches/build_file_checksums.ser 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | .DS_Store 9 | /build 10 | /captures 11 | .externalNativeBuild 12 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/splitebitmap/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.toly1994.splitebitmap; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | 6 | public class MainActivity extends AppCompatActivity { 7 | 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | setContentView(R.layout.activity_main); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/test/java/com/toly1994/splitebitmap/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.toly1994.splitebitmap; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/splitebitmap/Ball.java: -------------------------------------------------------------------------------- 1 | package com.toly1994.splitebitmap; 2 | 3 | /** 4 | * 作者:张风捷特烈
5 | * 时间:2018/11/16 0016:21:51
6 | * 邮箱:1981462002@qq.com
7 | * 说明:粒子对象 8 | */ 9 | public class Ball implements Cloneable { 10 | public float aX;//加速度 11 | public float aY;//加速度Y 12 | public float vX;//速度X 13 | public float vY;//速度Y 14 | public float x;//点位X 15 | public float y;//点位Y 16 | public int color;//颜色 17 | public float r;//半径 18 | public long born;//诞生时间 19 | 20 | public Ball clone() { 21 | Ball clone = null; 22 | try { 23 | clone = (Ball) super.clone(); 24 | } catch (CloneNotSupportedException e) { 25 | e.printStackTrace(); 26 | } 27 | return clone; 28 | } 29 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/toly1994/splitebitmap/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.toly1994.splitebitmap; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.toly1994.splitebitmap", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 27 5 | defaultConfig { 6 | applicationId "com.toly1994.splitebitmap" 7 | minSdkVersion 21 8 | targetSdkVersion 27 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | compileOptions { 20 | sourceCompatibility = '1.8' 21 | targetCompatibility = '1.8' 22 | } 23 | } 24 | 25 | dependencies { 26 | implementation fileTree(dir: 'libs', include: ['*.jar']) 27 | implementation 'com.android.support:appcompat-v7:27.1.1' 28 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 29 | testImplementation 'junit:junit:4.12' 30 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 31 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 32 | } 33 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | -------------------------------------------------------------------------------- /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 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 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 Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 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 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 11 | 16 | 21 | 26 | 31 | 36 | 41 | 46 | 51 | 56 | 61 | 66 | 71 | 76 | 81 | 86 | 91 | 96 | 101 | 106 | 111 | 116 | 121 | 126 | 131 | 136 | 141 | 146 | 151 | 156 | 161 | 166 | 171 | 172 | -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/splitebitmap/BitmapTXTSplitView.java: -------------------------------------------------------------------------------- 1 | package com.toly1994.splitebitmap; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapFactory; 7 | import android.graphics.Canvas; 8 | import android.graphics.Color; 9 | import android.graphics.Paint; 10 | import android.graphics.Path; 11 | import android.graphics.Picture; 12 | import android.graphics.Point; 13 | import android.support.annotation.Nullable; 14 | import android.util.AttributeSet; 15 | import android.view.MotionEvent; 16 | import android.view.View; 17 | import android.view.animation.LinearInterpolator; 18 | 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | 24 | /** 25 | * 作者:张风捷特烈
26 | * 时间:2018/11/16 0016:17:07
27 | * 邮箱:1981462002@qq.com
28 | * 说明: 29 | */ 30 | public class BitmapTXTSplitView extends View { 31 | private Point mCoo = new Point(600, 300);//坐标系 32 | private Picture mCooPicture;//坐标系canvas元件 33 | private Picture mGridPicture;//网格canvas元件 34 | private Paint mHelpPint;//辅助画笔 35 | 36 | 37 | private Paint mPaint;//主画笔 38 | private Path mPath;//主路径 39 | private Bitmap mBitmap; 40 | private int[][] mColArr; 41 | 42 | 43 | 44 | private List mBalls = new ArrayList<>();//粒子集合 45 | private ValueAnimator mAnimator;//时间流 46 | private long mRunTime;//粒子运动时刻 47 | private boolean isOK;//结束的flag 48 | private int curBitmapIndex = 0;//当前图片索引 49 | private Bitmap[] mBitmaps;//图片数组 50 | 51 | public BitmapTXTSplitView(Context context) { 52 | this(context, null); 53 | } 54 | 55 | public BitmapTXTSplitView(Context context, @Nullable AttributeSet attrs) { 56 | super(context, attrs); 57 | init();//初始化 58 | } 59 | 60 | private void init() { 61 | //初始化主画笔 62 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 63 | mPaint.setColor(Color.BLUE); 64 | mPaint.setStrokeWidth(5); 65 | //初始化主路径 66 | mPath = new Path(); 67 | 68 | 69 | 70 | //初始化时间流ValueAnimator 71 | mAnimator = ValueAnimator.ofFloat(0, 1); 72 | mAnimator.setRepeatCount(-1); 73 | mAnimator.setDuration(2000); 74 | mAnimator.setInterpolator(new LinearInterpolator()); 75 | mAnimator.addUpdateListener(animation -> { 76 | updateBall();//更新小球位置 77 | invalidate(); 78 | }); 79 | 80 | 81 | //加载图片数组 82 | mBitmaps = new Bitmap[]{ 83 | BitmapFactory.decodeResource(getResources(), R.mipmap.thank_you), 84 | BitmapFactory.decodeResource(getResources(), R.mipmap.bye), 85 | BitmapFactory.decodeResource(getResources(), R.mipmap.go_on) 86 | }; 87 | 88 | bitmap2Ball(mBitmaps[curBitmapIndex]); 89 | 90 | // int color_0_0 = bitmap.getPixel(0, 0); 91 | // mPaint.setColor(color_0_0); 92 | 93 | // mColArr = new int[bitmap.getWidth()][bitmap.getHeight()]; 94 | 95 | // mBalls = initBall(bitmap.getWidth(), bitmap.getHeight()); 96 | 97 | 98 | // Bitmap newBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig()); 99 | 100 | 101 | // //将newBitmap加入画板 102 | // Canvas canvas = new Canvas(newBitmap); 103 | // //准备画笔 104 | // Paint paint = new Paint(); 105 | // //将按照原作图片绘制在新图 106 | // canvas.drawBitmap(bitmap, 0, 0, paint); 107 | 108 | 109 | } 110 | 111 | @Override 112 | protected void onDraw(Canvas canvas) { 113 | super.onDraw(canvas); 114 | canvas.save(); 115 | canvas.translate(mCoo.x, mCoo.y); 116 | for (Ball ball : mBalls) { 117 | mPaint.setColor(ball.color); 118 | canvas.drawCircle(ball.x, ball.y, 2, mPaint); 119 | } 120 | 121 | //TODO ----drawSomething 122 | canvas.restore(); 123 | // HelpDraw.draw(canvas, mGridPicture, mCooPicture); 124 | } 125 | 126 | @Override 127 | public boolean onTouchEvent(MotionEvent event) { 128 | switch (event.getAction()) { 129 | case MotionEvent.ACTION_DOWN: 130 | mRunTime = System.currentTimeMillis();//记录点击时间 131 | mAnimator.start(); 132 | break; 133 | case MotionEvent.ACTION_UP: 134 | // mAnimator.pause(); 135 | break; 136 | } 137 | return true; 138 | } 139 | 140 | 141 | /** 142 | * 更新小球 143 | */ 144 | private void updateBall() { 145 | for (int i = 0; i < mBalls.size(); i++) { 146 | Ball ball = mBalls.get(i); 147 | if (System.currentTimeMillis() - mRunTime > 2000) { 148 | mBalls.remove(i); 149 | } 150 | 151 | if (mBalls.isEmpty()) {//表示本张已结束 152 | if (curBitmapIndex == 2) { 153 | mAnimator.end(); 154 | return; 155 | } 156 | curBitmapIndex++; 157 | bitmap2Ball(mBitmaps[curBitmapIndex]); 158 | 159 | isOK = true; 160 | 161 | invalidate(); 162 | mRunTime = System.currentTimeMillis(); 163 | mAnimator.pause(); 164 | } 165 | 166 | if (isOK) {//如果本张结束---返回掉 167 | isOK = false; 168 | return; 169 | } 170 | 171 | ball.x += ball.vX; 172 | ball.y += ball.vY; 173 | ball.vY += ball.aY; 174 | ball.vX += ball.aX; 175 | } 176 | } 177 | 178 | 179 | private List initBall(int w, int h) { 180 | for (int i = 0; i < w; i++) { 181 | for (int j = 0; j < h; j++) { 182 | Ball ball = new Ball(); 183 | ball.vX = (float) (Math.pow(-1, Math.ceil(Math.random() * 1000)) * 20 * Math.random()); 184 | ball.vY = rangeInt(-15, 35); 185 | ball.aY = 0.98f; 186 | ball.x = i * 4; 187 | ball.y = j * 4; 188 | ball.color = mColArr[i][j]; 189 | mBalls.add(ball); 190 | } 191 | } 192 | return mBalls; 193 | } 194 | 195 | /** 196 | * 获取范围随机整数:如 rangeInt(1,9) 197 | * 198 | * @param s 前数(包括) 199 | * @param e 后数(包括) 200 | * @return 范围随机整数 201 | */ 202 | public static int rangeInt(int s, int e) { 203 | int max = Math.max(s, e); 204 | int min = Math.min(s, e) - 1; 205 | return (int) (min + Math.ceil(Math.random() * (max - min))); 206 | } 207 | 208 | /** 209 | * 将一个图片粒子化 210 | * @param bitmap 211 | */ 212 | public void bitmap2Ball(Bitmap bitmap) { 213 | for (int i = 0; i < bitmap.getWidth(); i++) { 214 | for (int j = 0; j < bitmap.getHeight(); j++) { 215 | int pixel = bitmap.getPixel(i, j); 216 | if (pixel < 0) {//此处过滤掉其他颜色,避免全部产生粒子 217 | Ball ball = new Ball();//产生粒子---每个粒子拥有随机的一些属性信息 218 | ball.vX = (float) (Math.pow(-1, Math.ceil(Math.random() * 1000)) * 20 * Math.random()); 219 | ball.vY = rangeInt(-15, 35); 220 | ball.aY = 0.98f; 221 | ball.x = i * 4; 222 | ball.y = j * 4; 223 | ball.color = pixel; 224 | ball.born = System.currentTimeMillis(); 225 | mBalls.add(ball); 226 | } 227 | } 228 | } 229 | } 230 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #### 零、前言 2 | >1.第一次接触粒子是在html5的canvas,说是html的canvas,倒不如说是JavaScript的canvas,毕竟核心都在js。 3 | 2.经过长久的酝酿,感觉Java实现粒子运动好像也不是什么难事,今天将用Android作为视口,带你领略粒子的炫酷。 4 | 3.关于性能方面,我想只要合理控制粒子的消失,还是可以接受的。只要不是无限级别,和游戏比起来,这点性能九牛一毛啦。 5 | 4.粒子效果的核心有三个点:收集粒子、更改粒子、显示粒子 6 | 5.为了纯粹,本文只实现下图的粒子效果: 7 | 8 | ![粒子效果](https://upload-images.jianshu.io/upload_images/9414344-f8514775af20c7de.gif?imageMogr2/auto-orient/strip) 9 | 10 | #### 一、文字的粒子化思路 11 | 12 | ##### 1.资源准备 13 | 14 | >经过我的思索,既然可以用二维数组实现数字的粒子化:[见:Android原生绘图之炫酷倒计时](https://www.jianshu.com/p/dd8e325b2ae3), 15 | 那么一个Bitmap不是天然包含一个二维的像素数组吗?二话不说,将图片调成黑字无底,遍历添加。 16 | 17 | ![准备图片.png](https://upload-images.jianshu.io/upload_images/9414344-46ec5116616f9785.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 18 | 19 | --- 20 | 21 | ##### 2.粒子对象 22 | 23 | ``` 24 | /** 25 | * 作者:张风捷特烈
26 | * 时间:2018/11/16 0016:21:51
27 | * 邮箱:1981462002@qq.com
28 | * 说明:粒子对象 29 | */ 30 | public class Ball implements Cloneable { 31 | public float aX;//加速度 32 | public float aY;//加速度Y 33 | public float vX;//速度X 34 | public float vY;//速度Y 35 | public float x;//点位X 36 | public float y;//点位Y 37 | public int color;//颜色 38 | public float r;//半径 39 | public long born;//诞生时间 40 | 41 | public Ball clone() { 42 | Ball clone = null; 43 | try { 44 | clone = (Ball) super.clone(); 45 | } catch (CloneNotSupportedException e) { 46 | e.printStackTrace(); 47 | } 48 | return clone; 49 | } 50 | } 51 | ``` 52 | 53 | --- 54 | 55 | ##### 3.对粒子的收集 56 | 57 | >这里遍历一下bitmap将所有的黑色像素收集到粒子集合中: 58 | 59 | 60 | ``` 61 | //成员变量: 62 | private List mBalls = new ArrayList<>();//粒子集合 63 | //加载图片 64 | Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.thank_you); 65 | for (int i = 0; i < bitmap.getWidth(); i++) { 66 | for (int j = 0; j < bitmap.getHeight(); j++) { 67 | int pixel = bitmap.getPixel(i, j); 68 | if (pixel < 0) {//此处过滤掉其他颜色,避免全部产生粒子 69 | Ball ball = new Ball();//产生粒子---每个粒子拥有随机的一些属性信息 70 | ball.vX = (float) (Math.pow(-1, Math.ceil(Math.random() 71 | ball.vY = rangeInt(-15, 35); 72 | ball.aY = 0.98f; 73 | ball.x = i * 4; 74 | ball.y = j * 4; 75 | ball.color = pixel; 76 | ball.born = System.currentTimeMillis(); 77 | mBalls.add(ball); 78 | } 79 | mColArr[i][j] = bitmap.getPixel(i, j); 80 | } 81 | } 82 | ``` 83 | 84 | --- 85 | 86 | ##### 4.粒子的显示 87 | >也就是将粒子集合中的每个粒子绘制出来,非常简单 88 | 但这时它已经不是文字或图片了,而是可操纵的粒子,是不是很兴奋 89 | 90 | 91 | ``` 92 | @Override 93 | protected void onDraw(Canvas canvas) { 94 | super.onDraw(canvas); 95 | canvas.save(); 96 | canvas.translate(mCoo.x, mCoo.y); 97 | for (Ball ball : mBalls) {//绘制小球集合 98 | mPaint.setColor(ball.color); 99 | canvas.drawCircle(ball.x, ball.y, 2, mPaint); 100 | } 101 | canvas.restore(); 102 | } 103 | ``` 104 | 105 | --- 106 | #### 二、粒子的运动思路 107 | 108 | >结核运动学的一点知识,让小球拥有位移,速度,加速度的模拟,来实现运动,这里不过多赘述 109 | [我的这篇文章讲得非常细致](https://juejin.im/post/5bee10376fb9a04a0e2cc4c2)。 110 | 111 | 112 | ![thank_you.gif](https://upload-images.jianshu.io/upload_images/9414344-f911e2145cc7420b.gif?imageMogr2/auto-orient/strip) 113 | 114 | ##### 1.粒子的状态更新: 115 | >其实也不复杂,就是在恒定时间流下对位移和速度进行运动学的累加 116 | 117 | ``` 118 | /** 119 | * 更新小球 120 | */ 121 | private void updateBall() { 122 | for (int i = 0; i < mBalls.size(); i++) { 123 | Ball ball = mBalls.get(i); 124 | ball.x += ball.vX; 125 | ball.y += ball.vY; 126 | ball.vY += ball.aY; 127 | ball.vX += ball.aX; 128 | } 129 | } 130 | ``` 131 | 132 | ##### 2.粒子的湮灭 133 | >昨天在思考怎么能够更好控制粒子的湮灭呢? 134 | 粒子的湮灭说起来就是在一定的条件下将粒子从集合中移除,今早突然灵光一闪,可以用时间啊! 135 | 136 | ``` 137 | /** 138 | * 更新小球 139 | */ 140 | private void updateBall() { 141 | for (int i = 0; i < mBalls.size(); i++) { 142 | Ball ball = mBalls.get(i); 143 | if (System.currentTimeMillis() - mClickTime > 3000) 144 | mBalls.remove(i); 145 | } 146 | ball.x += ball.vX; 147 | ball.y += ball.vY; 148 | ball.vY += ball.aY; 149 | ball.vX += ball.aX; 150 | } 151 | } 152 | ``` 153 | 154 | ##### 3.时间数字流: 155 | 156 | ``` 157 | //初始化时间流ValueAnimator 158 | mAnimator = ValueAnimator.ofFloat(0, 1); 159 | mAnimator.setRepeatCount(-1); 160 | mAnimator.setDuration(2000); 161 | mAnimator.addUpdateListener(animation -> { 162 | updateBall();//更新小球位置 163 | invalidate(); 164 | }); 165 | ``` 166 | 167 | ##### 4.点击事件 168 | 169 | ``` 170 | @Override 171 | public boolean onTouchEvent(MotionEvent event) { 172 | switch (event.getAction()) { 173 | case MotionEvent.ACTION_DOWN: 174 | mClickTime = System.currentTimeMillis();//记录点击时间 175 | mAnimator.start(); 176 | break; 177 | } 178 | return true; 179 | } 180 | ``` 181 | 182 | >这样粒子运动的效果就实现了,当然你也可以用任意的图片来进行粒子运动 183 | 关于Bitmap的粒子运动会新写一篇来详细的论述,敬请期待。 184 | --- 185 | #### 三、粒子动画结束监听: 186 | >现在到了粒子全部湮灭的监听了,在一张图片的所有粒子湮灭后进入下一个图片: 187 | 很容易想到在移除粒子是监听粒子集合是否为空 188 | 189 | ##### 1.成员变量准备 190 | 191 | ``` 192 | private List mBalls = new ArrayList<>();//粒子集合 193 | private ValueAnimator mAnimator;//时间流 194 | private long mRunTime;//粒子运动时刻 195 | private boolean isOK;//结束的flag 196 | private int curBitmapIndex = 0;//当前图片索引 197 | private Bitmap[] mBitmaps;//图片数组 198 | ``` 199 | 200 | ##### 2.图片粒子化方法方法封装 201 | 202 | ``` 203 | /** 204 | * 将一个图片粒子化 205 | * @param bitmap 206 | */ 207 | public void bitmap2Ball(Bitmap bitmap) { 208 | for (int i = 0; i < bitmap.getWidth(); i++) { 209 | for (int j = 0; j < bitmap.getHeight(); j++) { 210 | int pixel = bitmap.getPixel(i, j); 211 | if (pixel < 0) {//此处过滤掉其他颜色,避免全部产生粒子 212 | Ball ball = new Ball();//产生粒子---每个粒子拥有随机的一些属性信息 213 | ball.vX = (float) (Math.pow(-1, Math.ceil(Math.random() * 1000)) * 20 * Math.random()); 214 | ball.vY = rangeInt(-15, 35); 215 | ball.aY = 0.98f; 216 | ball.x = i * 4; 217 | ball.y = j * 4; 218 | ball.color = pixel; 219 | ball.born = System.currentTimeMillis(); 220 | mBalls.add(ball); 221 | } 222 | } 223 | } 224 | } 225 | ``` 226 | 227 | 228 | ##### 3.准备一个图片数组: 229 | 230 | ``` 231 | //加载图片数组 232 | mBitmaps = new Bitmap[]{ 233 | BitmapFactory.decodeResource(getResources(), R.mipmap.thank_you), 234 | BitmapFactory.decodeResource(getResources(), R.mipmap.bye), 235 | BitmapFactory.decodeResource(getResources(), R.mipmap.go_on) 236 | }; 237 | bitmap2Ball(mBitmaps[curBitmapIndex]);//初始化第一张图 238 | ``` 239 | 240 | ##### 4.监听图片碎裂未完成,进行下一张 241 | >isOK这个flag让我头疼了几分钟,总算找到了何时的位置 242 | 243 | ``` 244 | /** 245 | * 更新小球 246 | */ 247 | private void updateBall() { 248 | for (int i = 0; i < mBalls.size(); i++) { 249 | Ball ball = mBalls.get(i); 250 | if (System.currentTimeMillis() - mRunTime > 2000) { 251 | mBalls.remove(i); 252 | } 253 | if (mBalls.isEmpty()) {//表示本张已结束 254 | if (curBitmapIndex == 2) { 255 | mAnimator.end(); 256 | return; 257 | } 258 | curBitmapIndex++; 259 | bitmap2Ball(mBitmaps[curBitmapIndex]); 260 | isOK = true; 261 | invalidate(); 262 | mRunTime = System.currentTimeMillis(); 263 | mAnimator.pause(); 264 | } 265 | if (isOK) {//如果本张结束---返回掉 266 | isOK = false; 267 | return; 268 | } 269 | 270 | ball.x += ball.vX; 271 | ball.y += ball.vY; 272 | ball.vY += ball.aY; 273 | ball.vX += ball.aX; 274 | } 275 | } 276 | ``` 277 | 278 | ![粒子效果](https://upload-images.jianshu.io/upload_images/9414344-f8514775af20c7de.gif?imageMogr2/auto-orient/strip) 279 | 280 | 281 | >至此,本文的效果就已经实现了,是不是没有想象中的那么复杂,相信你也可以做到 282 | 283 | 284 | --- 285 | 286 | #### 四、后记: 287 | 288 | >这些天感谢柚子茶的帮助,无以为报,以文记之,祝掘金越来越好,帮助更多的技术开发者。 289 | 本文`捷文规范`,不会再做任何修改。项目源码见[→_→ ~ GitHub ~ ←_←](https://note.youdao.com/) 290 | ----------------------------2018.11.17--捷特 &安徽 -------------------------------------------------------------------------------- /app/src/main/java/com/toly1994/splitebitmap/BitmapSplitView.java: -------------------------------------------------------------------------------- 1 | package com.toly1994.splitebitmap; 2 | 3 | 4 | import android.animation.ValueAnimator; 5 | import android.content.Context; 6 | import android.graphics.Bitmap; 7 | import android.graphics.BitmapFactory; 8 | import android.graphics.Canvas; 9 | import android.graphics.Color; 10 | import android.graphics.Paint; 11 | import android.graphics.Path; 12 | import android.graphics.Picture; 13 | import android.graphics.Point; 14 | import android.support.annotation.Nullable; 15 | import android.util.AttributeSet; 16 | import android.view.MotionEvent; 17 | import android.view.View; 18 | import android.view.animation.LinearInterpolator; 19 | 20 | 21 | import java.io.File; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | 27 | /** 28 | * 作者:张风捷特烈
29 | * 时间:2018/11/16 0016:17:07
30 | * 邮箱:1981462002@qq.com
31 | * 说明: 32 | */ 33 | public class BitmapSplitView extends View { 34 | private Point mCoo = new Point(800, 400);//坐标系 35 | private Picture mCooPicture;//坐标系canvas元件 36 | private Picture mGridPicture;//网格canvas元件 37 | private Paint mHelpPint;//辅助画笔 38 | 39 | 40 | private Paint mPaint;//主画笔 41 | private Path mPath;//主路径 42 | private Bitmap mBitmap; 43 | private int[][] mColArr; 44 | 45 | private int d = 3;//复刻的像素边长 46 | private List mBalls = new ArrayList<>();//粒子集合 47 | private ValueAnimator mAnimator;//时间流 48 | private long mRunTime;//粒子运动时刻 49 | private boolean isOK;//结束的flag 50 | private int curBitmapIndex = 0;//当前图片索引 51 | private Bitmap[] mBitmaps;//图片数组 52 | 53 | public BitmapSplitView(Context context) { 54 | this(context, null); 55 | } 56 | 57 | public BitmapSplitView(Context context, @Nullable AttributeSet attrs) { 58 | super(context, attrs); 59 | init();//初始化 60 | } 61 | 62 | private void init() { 63 | //初始化主画笔 64 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 65 | mPaint.setColor(Color.BLUE); 66 | mPaint.setStrokeWidth(5); 67 | //初始化主路径 68 | mPath = new Path(); 69 | 70 | 71 | //初始化时间流ValueAnimator 72 | mAnimator = ValueAnimator.ofFloat(0, 1); 73 | mAnimator.setRepeatCount(-1); 74 | mAnimator.setDuration(2000); 75 | mAnimator.setInterpolator(new LinearInterpolator()); 76 | mAnimator.addUpdateListener(animation -> { 77 | updateBall();//更新小球位置 78 | invalidate(); 79 | }); 80 | 81 | 82 | //加载图片数组 83 | mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.iv_100x100); 84 | // 85 | // 86 | // int color_0_0 = mBitmap.getPixel(0, 0); 87 | // L.d(color_0_0 + L.l()); 88 | // mPaint.setColor(color_0_0); 89 | 90 | 91 | Bitmap bitmap = Bitmap.createBitmap(2, 2, Bitmap.Config.ARGB_8888); 92 | bitmap.setPixel(0, 0, Color.BLACK); 93 | bitmap.setPixel(1, 0, Color.RED); 94 | bitmap.setPixel(0, 1, Color.WHITE); 95 | bitmap.setPixel(1, 1, Color.BLUE); 96 | 97 | // saveBitmap(Environment.getExternalStorageDirectory() + "/testC/toly/px_2x2.png", bitmap); 98 | 99 | int pixel_0_0 = bitmap.getPixel(0, 0); 100 | int pixel_1_0 = bitmap.getPixel(1, 0); 101 | int pixel_0_1 = bitmap.getPixel(0, 1); 102 | int pixel_1_1 = bitmap.getPixel(1, 1); 103 | 104 | // L.d("pixel_0_0:" + pixel_0_0 + L.l()); 105 | // L.d("pixel_1_0:" + pixel_1_0 + L.l()); 106 | // L.d("pixel_0_1:" + pixel_0_1 + L.l()); 107 | // L.d("pixel_1_1:" + pixel_1_1 + L.l()); 108 | 109 | printColor("pixel_0_0", pixel_0_0);//黑:a:255, r:0, g:0, b:0 110 | printColor("pixel_1_0", pixel_1_0);//红:a:255, r:255, g:0, b:0 111 | printColor("pixel_0_1", pixel_0_1);//白:a:255, r:255, g:255, b:255 112 | printColor("pixel_1_1", pixel_1_1);//蓝:a:255, r:0, g:0, b:255 113 | 114 | 115 | // pixel = -65536; 116 | // int a = Color.alpha(pixel); 117 | // int r = Color.red(pixel); 118 | // int g = Color.green(pixel); 119 | // int b = Color.blue(pixel); 120 | 121 | 122 | // mColArr = new int[bitmap.getWidth()][bitmap.getHeight()]; 123 | 124 | // mBalls = initBall(bitmap.getWidth(), bitmap.getHeight()); 125 | 126 | 127 | // Bitmap newBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig()); 128 | 129 | 130 | // //将newBitmap加入画板 131 | // Canvas canvas = new Canvas(newBitmap); 132 | // //准备画笔 133 | // Paint paint = new Paint(); 134 | // //将按照原作图片绘制在新图 135 | // canvas.drawBitmap(bitmap, 0, 0, paint); 136 | 137 | initBall(mBitmap); 138 | } 139 | 140 | /** 141 | * 将颜色从int 拆分成argb,并打印出来 142 | * 143 | * @param msg 144 | * @param color 145 | */ 146 | private void printColor(String msg, int color) { 147 | int a = Color.alpha(color); 148 | int r = Color.red(color); 149 | int g = Color.green(color); 150 | int b = Color.blue(color); 151 | // L.d(msg + "----a:" + a + ", r:" + r + ", g:" + g + ", b:" + b + L.l()); 152 | } 153 | 154 | 155 | @Override 156 | protected void onDraw(Canvas canvas) { 157 | super.onDraw(canvas); 158 | canvas.save(); 159 | canvas.translate(mCoo.x, mCoo.y); 160 | // drawBitmapWithStar(canvas); 161 | 162 | for (Ball ball : mBalls) { 163 | mPaint.setColor(ball.color); 164 | // canvas.drawRect( 165 | // ball.x - d / 2, ball.y - d / 2, ball.x + d / 2, ball.y + d / 2, mPaint); 166 | 167 | canvas.drawCircle(ball.x, ball.y, d/2, mPaint); 168 | } 169 | canvas.restore(); 170 | // HelpDraw.draw(canvas, mGridPicture, mCooPicture); 171 | } 172 | 173 | private void drawBitmapWithStar(Canvas canvas) { 174 | for (int i = 0; i < mBalls.size(); i++) { 175 | canvas.save(); 176 | int line = i % mBitmap.getHeight(); 177 | int row = i / mBitmap.getWidth(); 178 | canvas.translate(row * 2 * d, line * 2 * d); 179 | mPaint.setColor(mBalls.get(i).color); 180 | // canvas.drawPath(CommonPath.nStarPath(5, d, d / 2), mPaint); 181 | canvas.restore(); 182 | 183 | } 184 | } 185 | 186 | @Override 187 | public boolean onTouchEvent(MotionEvent event) { 188 | switch (event.getAction()) { 189 | case MotionEvent.ACTION_DOWN: 190 | mRunTime = System.currentTimeMillis();//记录点击时间 191 | mAnimator.start(); 192 | break; 193 | case MotionEvent.ACTION_UP: 194 | // mAnimator.pause(); 195 | break; 196 | } 197 | return true; 198 | } 199 | 200 | 201 | /** 202 | * 更新小球 203 | */ 204 | private void updateBall() { 205 | for (int i = 0; i < mBalls.size(); i++) { 206 | Ball ball = mBalls.get(i); 207 | if (System.currentTimeMillis() - mRunTime > 2000) { 208 | mBalls.remove(i); 209 | } 210 | ball.x += ball.vX; 211 | ball.y += ball.vY; 212 | ball.vY += ball.aY; 213 | ball.vX += ball.aX; 214 | } 215 | } 216 | 217 | /** 218 | * 根像素初始化粒子 219 | * 220 | * @param bitmap 221 | * @return 222 | */ 223 | private void initBall(Bitmap bitmap) { 224 | for (int i = 0; i < bitmap.getHeight(); i++) { 225 | for (int j = 0; j < bitmap.getWidth(); j++) { 226 | Ball ball = new Ball();//产生粒子---每个粒子拥有随机的一些属性信息 227 | ball.x = i * d + d / 2; 228 | ball.y = j * d + d / 2; 229 | ball.vX = (float) (Math.pow(-1, Math.ceil(Math.random() * 1001)) * 40 * Math.random()); 230 | ball.vY = 0; 231 | ball.aX = 0.98f; 232 | ball.color = bitmap.getPixel(i, j); 233 | ball.born = System.currentTimeMillis(); 234 | mBalls.add(ball); 235 | } 236 | } 237 | } 238 | 239 | /** 240 | * 配凑黑白颜色 241 | * 242 | * @param a 243 | * @param r 244 | * @param g 245 | * @param b 246 | * @return 247 | */ 248 | private int blackAndWhite(int a, int r, int g, int b) { 249 | //拼凑出新的颜色 250 | int grey = (int) (r * 0.3 + g * 0.59 + b * 0.11); 251 | if (grey > 255 / 2) { 252 | grey = 255; 253 | } else { 254 | grey = 0; 255 | } 256 | return Color.argb(a, grey, grey, grey); 257 | } 258 | 259 | /** 260 | * 配凑灰颜色 261 | * 262 | * @param a 263 | * @param r 264 | * @param g 265 | * @param b 266 | * @return 267 | */ 268 | private int grey(int a, int r, int g, int b) { 269 | //拼凑出新的颜色 270 | int grey = (int) (r * 0.3 + g * 0.59 + b * 0.11); 271 | return Color.argb(a, grey, grey, grey); 272 | } 273 | 274 | // 275 | private int reverse(int a, int r, int g, int b) { 276 | //拼凑出新的颜色 277 | return Color.argb(a, 255 - r, 255 - g, 255 - b); 278 | } 279 | 280 | /** 281 | * 获取范围随机整数:如 rangeInt(1,9) 282 | * 283 | * @param s 前数(包括) 284 | * @param e 后数(包括) 285 | * @return 范围随机整数 286 | */ 287 | public static int rangeInt(int s, int e) { 288 | int max = Math.max(s, e); 289 | int min = Math.min(s, e) - 1; 290 | return (int) (min + Math.ceil(Math.random() * (max - min))); 291 | } 292 | 293 | /** 294 | * 将一个图片粒子化 295 | * 296 | * @param bitmap 297 | */ 298 | public void bitmap2Ball(Bitmap bitmap) { 299 | for (int i = 0; i < bitmap.getWidth(); i++) { 300 | for (int j = 0; j < bitmap.getHeight(); j++) { 301 | int pixel = bitmap.getPixel(i, j); 302 | if (pixel < 0) {//此处过滤掉其他颜色,避免全部产生粒子 303 | Ball ball = new Ball();//产生粒子---每个粒子拥有随机的一些属性信息 304 | ball.vX = (float) (Math.pow(-1, Math.ceil(Math.random() * 1000)) * 20 * Math.random()); 305 | ball.vY = rangeInt(-15, 35); 306 | ball.aY = 0.98f; 307 | ball.x = i * 4; 308 | ball.y = j * 4; 309 | ball.color = pixel; 310 | ball.born = System.currentTimeMillis(); 311 | mBalls.add(ball); 312 | } 313 | } 314 | } 315 | } 316 | 317 | /** 318 | * 保存bitmap到本地 319 | * 320 | * @param path 路径 321 | * @param mBitmap 图片 322 | * @return 路径 323 | */ 324 | public static String saveBitmap(String path, Bitmap mBitmap) { 325 | 326 | File file = new File(path); 327 | if (file.isDirectory()) { 328 | return null; 329 | } 330 | 331 | if (!file.exists()) { 332 | file.getParentFile().mkdirs(); 333 | try { 334 | file.createNewFile(); 335 | } catch (IOException e) { 336 | e.printStackTrace(); 337 | } 338 | } 339 | try { 340 | FileOutputStream fos = new FileOutputStream(file); 341 | mBitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); 342 | fos.flush(); 343 | fos.close(); 344 | } catch (IOException e) { 345 | e.printStackTrace(); 346 | return null; 347 | } 348 | return file.getAbsolutePath(); 349 | } 350 | } --------------------------------------------------------------------------------