├── .gitignore
├── README.md
├── StickerView.iml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── sample
├── .gitignore
├── build.gradle
├── proguard-rules.pro
├── sample.iml
└── src
│ ├── androidTest
│ └── java
│ │ └── me
│ │ └── isming
│ │ └── sticker
│ │ └── ApplicationTest.java
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── me
│ │ └── isming
│ │ └── sticker
│ │ └── MainActivity.java
│ └── res
│ ├── drawable-xhdpi
│ └── hello.jpg
│ ├── layout
│ └── activity_main.xml
│ ├── menu
│ └── menu_main.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── settings.gradle
└── stickerviewLib
├── .gitignore
├── build.gradle
├── proguard-rules.pro
├── src
├── androidTest
│ └── java
│ │ └── me
│ │ └── isming
│ │ └── sticker
│ │ └── library
│ │ └── ApplicationTest.java
└── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── me
│ │ └── isming
│ │ └── sticker
│ │ └── library
│ │ ├── DisplayUtil.java
│ │ └── StickerView.java
│ └── res
│ ├── drawable-xhdpi
│ ├── ic_sticker_control.png
│ └── ic_sticker_delete.png
│ ├── drawable
│ ├── ic_sticker_reversal_horizontal.png
│ └── ic_sticker_reversal_vertical.png
│ └── values
│ └── strings.xml
└── stickerviewLib.iml
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | /.idea/libraries
5 | .DS_Store
6 | /build
7 | /captures
8 | .idea
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # StickerView For Android
2 |
3 | [](http://android-arsenal.com/details/1/1817)
4 |
5 | sticker view for android, can translate, scale, rotate.
6 |
7 | how it work: [http://blog.isming.me/2015/05/10/sticker-view/](http://blog.isming.me/2015/05/10/sticker-view/)
8 |
9 | ## how use it
10 |
11 | android studio 1.0+
12 | java 6+
13 | gradle plugin: 1.0+
14 |
15 | *sample* module is the demo
16 | *stickerviewLib* is the lib module, you can copy to your project
17 |
18 |
19 | ## About Me
20 | blog:[blog.isming.me](http://blog.isming.me)
21 |
22 | mail: linming1007@gmail.com
23 |
24 | weibo: [@码农明明桑](http://weibo.com/mingmingsang)
25 |
26 |
27 |
28 |
29 | ## License
30 | Copyright 2015 Isming.me
31 |
32 | Licensed under the Apache License, Version 2.0 (the "License");
33 | you may not use this file except in compliance with the License.
34 | You may obtain a copy of the License at
35 |
36 | http://www.apache.org/licenses/LICENSE-2.0
37 |
38 | Unless required by applicable law or agreed to in writing, software
39 | distributed under the License is distributed on an "AS IS" BASIS,
40 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
41 | See the License for the specific language governing permissions and
42 | limitations under the License.
43 |
--------------------------------------------------------------------------------
/StickerView.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:1.2.2'
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 |
--------------------------------------------------------------------------------
/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/sangmingming/StickerView/17df166f76d18c1f381fe271c78dfd1a3a998086/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
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.2.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/sample/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/sample/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 21
5 | buildToolsVersion "22.0.1"
6 |
7 | defaultConfig {
8 | applicationId "me.isming.sticker"
9 | minSdkVersion 10
10 | targetSdkVersion 21
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | compile project(":stickerviewLib")
25 | }
26 |
--------------------------------------------------------------------------------
/sample/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/sam/developer/android-sdk-macosx/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/sample/sample.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/sample/src/androidTest/java/me/isming/sticker/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package me.isming.sticker;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/sample/src/main/java/me/isming/sticker/MainActivity.java:
--------------------------------------------------------------------------------
1 | package me.isming.sticker;
2 |
3 | import android.app.Activity;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BitmapFactory;
6 | import android.os.Bundle;
7 | import android.view.Menu;
8 | import android.view.MenuItem;
9 | import android.view.ViewGroup;
10 | import android.widget.ImageView;
11 | import android.widget.RelativeLayout;
12 |
13 | import me.isming.sticker.library.StickerView;
14 |
15 |
16 | public class MainActivity extends Activity{
17 |
18 | @Override
19 | protected void onCreate(Bundle savedInstanceState) {
20 | super.onCreate(savedInstanceState);
21 | setContentView(R.layout.activity_main);
22 | ImageView imgView = (ImageView) findViewById(R.id.image);
23 | StickerView stickerView = new StickerView(this);
24 | RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
25 | ViewGroup.LayoutParams.MATCH_PARENT,
26 | ViewGroup.LayoutParams.MATCH_PARENT);
27 | params.addRule(RelativeLayout.ALIGN_BOTTOM, R.id.image);
28 | params.addRule(RelativeLayout.ALIGN_TOP, R.id.image);
29 | ((ViewGroup)imgView.getParent()).addView(stickerView, params);
30 | Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
31 | stickerView.setWaterMark(bitmap);
32 | }
33 |
34 | @Override
35 | public boolean onCreateOptionsMenu(Menu menu) {
36 | // Inflate the menu; this adds items to the action bar if it is present.
37 | getMenuInflater().inflate(R.menu.menu_main, menu);
38 | return true;
39 | }
40 |
41 | @Override
42 | public boolean onOptionsItemSelected(MenuItem item) {
43 | // Handle action bar item clicks here. The action bar will
44 | // automatically handle clicks on the Home/Up button, so long
45 | // as you specify a parent activity in AndroidManifest.xml.
46 | int id = item.getItemId();
47 |
48 | //noinspection SimplifiableIfStatement
49 | if (id == R.id.action_settings) {
50 | return true;
51 | }
52 |
53 | return super.onOptionsItemSelected(item);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-xhdpi/hello.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangmingming/StickerView/17df166f76d18c1f381fe271c78dfd1a3a998086/sample/src/main/res/drawable-xhdpi/hello.jpg
--------------------------------------------------------------------------------
/sample/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
10 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/sample/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangmingming/StickerView/17df166f76d18c1f381fe271c78dfd1a3a998086/sample/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangmingming/StickerView/17df166f76d18c1f381fe271c78dfd1a3a998086/sample/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangmingming/StickerView/17df166f76d18c1f381fe271c78dfd1a3a998086/sample/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangmingming/StickerView/17df166f76d18c1f381fe271c78dfd1a3a998086/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | StickerView
3 |
4 | Hello world!
5 | Settings
6 |
7 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':sample', ':stickerviewLib'
2 |
--------------------------------------------------------------------------------
/stickerviewLib/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/stickerviewLib/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 21
5 | buildToolsVersion "22.0.1"
6 |
7 | defaultConfig {
8 | minSdkVersion 10
9 | targetSdkVersion 21
10 | versionCode 1
11 | versionName "1.0"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | compile fileTree(dir: 'libs', include: ['*.jar'])
23 | compile 'com.android.support:appcompat-v7:22.1.0'
24 | }
25 |
--------------------------------------------------------------------------------
/stickerviewLib/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/sam/developer/android-sdk-macosx/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 |
--------------------------------------------------------------------------------
/stickerviewLib/src/androidTest/java/me/isming/sticker/library/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package me.isming.sticker.library;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/stickerviewLib/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/stickerviewLib/src/main/java/me/isming/sticker/library/DisplayUtil.java:
--------------------------------------------------------------------------------
1 | package me.isming.sticker.library;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.util.DisplayMetrics;
6 |
7 | public class DisplayUtil {
8 |
9 | /** 屏幕宽度 */
10 | private static int DisplayWidthPixels = 0;
11 | /** 屏幕高度 */
12 | private static int DisplayheightPixels = 0;
13 |
14 | /**
15 | * 获取屏幕参数
16 | * @param context
17 | */
18 | private static void getDisplayMetrics(Context context) {
19 | DisplayMetrics dm = new DisplayMetrics();
20 | ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(dm);
21 | DisplayWidthPixels = dm.widthPixels;// 宽度
22 | DisplayheightPixels = dm.heightPixels;// 高度
23 | }
24 |
25 | /**
26 | * 获取屏幕宽度
27 | * @param context
28 | * @return
29 | */
30 | public static int getDisplayWidthPixels(Context context) {
31 | if (context == null) {
32 | return -1;
33 | }
34 | if (DisplayWidthPixels == 0) {
35 | getDisplayMetrics(context);
36 | }
37 | return DisplayWidthPixels;
38 | }
39 |
40 | /**
41 | * 获取屏幕高度
42 | * @param context
43 | * @return
44 | */
45 | public static int getDisplayheightPixels(Context context) {
46 | if (context == null) {
47 | return -1;
48 | }
49 | if (DisplayheightPixels == 0) {
50 | getDisplayMetrics(context);
51 | }
52 | return DisplayheightPixels;
53 | }
54 |
55 | /**
56 | * 将px值转换为dip或dp值
57 | *
58 | * @param pxValue
59 | * @return
60 | */
61 | public static int px2dip(Context context, float pxValue) {
62 | final float scale = context.getResources().getDisplayMetrics().density;
63 | return (int) (pxValue / scale + 0.5f);
64 | }
65 |
66 | /**
67 | * 将dip或dp值转换为px值
68 | *
69 | * @param dipValue
70 | * @return
71 | */
72 | public static int dip2px(Context context, float dipValue) {
73 | if(context == null){
74 | return 0;
75 | }
76 | final float scale = context.getResources().getDisplayMetrics().density;
77 | return (int) (dipValue * scale + 0.5f);
78 | }
79 |
80 | /**
81 | * 将px值转换为sp值
82 | *
83 | * @param pxValue
84 | * @return
85 | */
86 | public static int px2sp(Context context, float pxValue) {
87 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
88 | return (int) (pxValue / fontScale + 0.5f);
89 | }
90 |
91 | /**
92 | * 将sp值转换为px值
93 | * @param spValue
94 | * @param spValue (DisplayMetrics类中属性scaledDensity)
95 | * @return
96 | */
97 | public static int sp2px(Context context, float spValue) {
98 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
99 | return (int) (spValue * fontScale + 0.5f);
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/stickerviewLib/src/main/java/me/isming/sticker/library/StickerView.java:
--------------------------------------------------------------------------------
1 | package me.isming.sticker.library;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BitmapFactory;
6 | import android.graphics.Canvas;
7 | import android.graphics.Color;
8 | import android.graphics.Matrix;
9 | import android.graphics.Paint;
10 | import android.graphics.RectF;
11 | import android.support.annotation.NonNull;
12 | import android.util.AttributeSet;
13 | import android.util.FloatMath;
14 | import android.util.Log;
15 | import android.view.MotionEvent;
16 | import android.view.View;
17 |
18 |
19 | /**
20 | * Created by sam on 14-8-14.
21 | */
22 | public class StickerView extends View {
23 |
24 | private float mScaleSize;
25 |
26 | public static final float MAX_SCALE_SIZE = 3.2f;
27 | public static final float MIN_SCALE_SIZE = 0.6f;
28 |
29 |
30 | private float[] mOriginPoints;
31 | private float[] mPoints;
32 | private RectF mOriginContentRect;
33 | private RectF mContentRect;
34 | private RectF mViewRect;
35 |
36 | private float mLastPointX, mLastPointY;
37 |
38 | private Bitmap mBitmap;
39 | private Bitmap mControllerBitmap, mDeleteBitmap;
40 | private Bitmap mReversalHorBitmap,mReversalVerBitmap;//水平反转和垂直反转bitmap
41 | private Matrix mMatrix;
42 | private Paint mPaint, mBorderPaint;
43 | private float mControllerWidth, mControllerHeight, mDeleteWidth, mDeleteHeight;
44 | private float mReversalHorWidth,mReversalHorHeight,mReversalVerWidth,mReversalVerHeight;
45 | private boolean mInController, mInMove;
46 | private boolean mInReversalHorizontal,mInReversalVertical;
47 |
48 | private boolean mDrawController = true;
49 | //private boolean mCanTouch;
50 | private float mStickerScaleSize = 1.0f;
51 |
52 | private OnStickerDeleteListener mOnStickerDeleteListener;
53 |
54 | public StickerView(Context context) {
55 | this(context, null);
56 | }
57 |
58 | public StickerView(Context context, AttributeSet attrs) {
59 | this(context, attrs, 0);
60 | }
61 |
62 | public StickerView(Context context, AttributeSet attrs, int defStyle) {
63 | super(context, attrs, defStyle);
64 | init();
65 | }
66 |
67 | private void init() {
68 |
69 | mPaint = new Paint();
70 | mPaint.setAntiAlias(true);
71 | mPaint.setFilterBitmap(true);
72 | mPaint.setStyle(Paint.Style.STROKE);
73 | mPaint.setStrokeWidth(4.0f);
74 | mPaint.setColor(Color.WHITE);
75 |
76 | mBorderPaint = new Paint(mPaint);
77 | mBorderPaint.setColor(Color.parseColor("#B2ffffff"));
78 | mBorderPaint.setShadowLayer(DisplayUtil.dip2px(getContext(), 2.0f), 0, 0, Color.parseColor("#33000000"));
79 |
80 | mControllerBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_sticker_control);
81 | mControllerWidth = mControllerBitmap.getWidth();
82 | mControllerHeight = mControllerBitmap.getHeight();
83 |
84 | mDeleteBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_sticker_delete);
85 | mDeleteWidth = mDeleteBitmap.getWidth();
86 | mDeleteHeight = mDeleteBitmap.getHeight();
87 |
88 | mReversalHorBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.ic_sticker_reversal_horizontal);
89 | mReversalHorWidth = mReversalHorBitmap.getWidth();
90 | mReversalHorHeight = mReversalHorBitmap.getHeight();
91 |
92 | mReversalVerBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.ic_sticker_reversal_vertical);
93 | mReversalVerWidth = mReversalVerBitmap.getWidth();
94 | mReversalVerHeight = mReversalVerBitmap.getHeight();
95 |
96 | }
97 |
98 | public void setWaterMark(@NonNull Bitmap bitmap) {
99 | mBitmap = bitmap;
100 | mStickerScaleSize = 1.0f;
101 |
102 |
103 | setFocusable(true);
104 | try {
105 |
106 |
107 | float px = mBitmap.getWidth();
108 | float py = mBitmap.getHeight();
109 |
110 |
111 | //mOriginPoints = new float[]{px, py, px + bitmap.getWidth(), py, bitmap.getWidth() + px, bitmap.getHeight() + py, px, py + bitmap.getHeight()};
112 | mOriginPoints = new float[]{0, 0, px, 0, px, py, 0, py, px / 2, py / 2};
113 | mOriginContentRect = new RectF(0, 0, px, py);
114 | mPoints = new float[10];
115 | mContentRect = new RectF();
116 |
117 | mMatrix = new Matrix();
118 | float transtLeft = ((float)DisplayUtil.getDisplayWidthPixels(getContext()) - mBitmap.getWidth()) / 2;
119 | float transtTop = ((float)DisplayUtil.getDisplayWidthPixels(getContext()) - mBitmap.getHeight()) / 2;
120 |
121 | mMatrix.postTranslate(transtLeft, transtTop);
122 |
123 | } catch (Exception e) {
124 | e.printStackTrace();
125 | }
126 | postInvalidate();
127 |
128 | }
129 |
130 | public Matrix getMarkMatrix() {
131 | return mMatrix;
132 | }
133 |
134 | @Override
135 | public void setFocusable(boolean focusable) {
136 | super.setFocusable(focusable);
137 | postInvalidate();
138 | }
139 |
140 | @Override
141 | protected void onDraw(Canvas canvas) {
142 | super.onDraw(canvas);
143 | if (mBitmap == null || mMatrix == null) {
144 | return;
145 | }
146 |
147 | mMatrix.mapPoints(mPoints, mOriginPoints);
148 |
149 | mMatrix.mapRect(mContentRect, mOriginContentRect);
150 | canvas.drawBitmap(mBitmap, mMatrix, mPaint);
151 | if (mDrawController && isFocusable()) {
152 | canvas.drawLine(mPoints[0], mPoints[1], mPoints[2], mPoints[3], mBorderPaint);
153 | canvas.drawLine(mPoints[2], mPoints[3], mPoints[4], mPoints[5], mBorderPaint);
154 | canvas.drawLine(mPoints[4], mPoints[5], mPoints[6], mPoints[7], mBorderPaint);
155 | canvas.drawLine(mPoints[6], mPoints[7], mPoints[0], mPoints[1], mBorderPaint);
156 | canvas.drawBitmap(mControllerBitmap, mPoints[4] - mControllerWidth / 2, mPoints[5] - mControllerHeight / 2, mBorderPaint);
157 | canvas.drawBitmap(mDeleteBitmap, mPoints[0] - mDeleteWidth / 2, mPoints[1] - mDeleteHeight / 2, mBorderPaint);
158 | canvas.drawBitmap(mReversalHorBitmap,mPoints[2]-mReversalHorWidth/2,mPoints[3]-mReversalVerHeight/2,mBorderPaint);
159 | canvas.drawBitmap(mReversalVerBitmap,mPoints[6]-mReversalVerWidth/2,mPoints[7]-mReversalVerHeight/2,mBorderPaint);
160 | }
161 | }
162 |
163 | public Bitmap getBitmap() {
164 | Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
165 | Canvas canvas = new Canvas(bitmap);
166 | mDrawController = false;
167 | draw(canvas);
168 | mDrawController = true;
169 | canvas.save();
170 | return bitmap;
171 | }
172 |
173 | public void setShowDrawController(boolean show) {
174 | mDrawController = show;
175 | }
176 |
177 |
178 | private boolean isInController(float x, float y) {
179 | int position = 4;
180 | //while (position < 8) {
181 | float rx = mPoints[position];
182 | float ry = mPoints[position + 1];
183 | RectF rectF = new RectF(rx - mControllerWidth / 2,
184 | ry - mControllerHeight / 2,
185 | rx + mControllerWidth / 2,
186 | ry + mControllerHeight / 2);
187 | if (rectF.contains(x, y)) {
188 | return true;
189 | }
190 | // position += 2;
191 | //}
192 | return false;
193 |
194 | }
195 |
196 | private boolean isInDelete(float x, float y) {
197 | int position = 0;
198 | //while (position < 8) {
199 | float rx = mPoints[position];
200 | float ry = mPoints[position + 1];
201 | RectF rectF = new RectF(rx - mDeleteWidth / 2,
202 | ry - mDeleteHeight / 2,
203 | rx + mDeleteWidth / 2,
204 | ry + mDeleteHeight / 2);
205 | if (rectF.contains(x, y)) {
206 | return true;
207 | }
208 | // position += 2;
209 | //}
210 | return false;
211 |
212 | }
213 | //判断点击区域是否在水平反转按钮区域内
214 | private boolean isInReversalHorizontal(float x,float y){
215 | int position = 2;
216 | float rx = mPoints[position];
217 | float ry = mPoints[position+1];
218 |
219 | RectF rectF = new RectF(rx - mReversalHorWidth/2,ry-mReversalHorHeight/2,rx+mReversalHorWidth/2,ry+mReversalHorHeight/2);
220 | if (rectF.contains(x,y))
221 | return true;
222 |
223 | return false;
224 |
225 | }
226 | //判断点击区域是否在垂直反转按钮区域内
227 | private boolean isInReversalVertical(float x,float y){
228 | int position = 6;
229 | float rx = mPoints[position];
230 | float ry = mPoints[position+1];
231 |
232 | RectF rectF = new RectF(rx - mReversalVerWidth/2,ry - mReversalVerHeight/2,rx + mReversalVerWidth/2,ry+mReversalVerHeight/2);
233 | if (rectF.contains(x,y))
234 | return true;
235 | return false;
236 | }
237 |
238 | private boolean mInDelete = false;
239 | @Override
240 | public boolean dispatchTouchEvent(MotionEvent event) {
241 | if (!isFocusable()) {
242 | return super.dispatchTouchEvent(event);
243 | }
244 | if (mViewRect == null) {
245 | mViewRect = new RectF(0f, 0f, getMeasuredWidth(), getMeasuredHeight());
246 | }
247 | float x = event.getX();
248 | float y = event.getY();
249 | switch (event.getAction()) {
250 | case MotionEvent.ACTION_DOWN:
251 | if (isInController(x, y)) {
252 | mInController = true;
253 | mLastPointY = y;
254 | mLastPointX = x;
255 | break;
256 | }
257 |
258 | if (isInDelete(x, y)) {
259 | mInDelete = true;
260 | break;
261 | }
262 |
263 | if(isInReversalHorizontal(x,y)){
264 | mInReversalHorizontal = true;
265 | break;
266 | }
267 |
268 | if(isInReversalVertical(x,y)){
269 | mInReversalVertical = true;
270 | break;
271 | }
272 |
273 | if (mContentRect.contains(x, y)) {
274 | mLastPointY = y;
275 | mLastPointX = x;
276 | mInMove = true;
277 | }
278 | break;
279 | case MotionEvent.ACTION_UP:
280 | if (isInDelete(x, y) && mInDelete) {
281 | doDeleteSticker();
282 | break;
283 | }
284 | if(isInReversalHorizontal(x,y) && mInReversalHorizontal){
285 | doReversalHorizontal();
286 | break;
287 | }
288 | if (isInReversalVertical(x,y) && mInReversalVertical){
289 | doReversalVertical();
290 | break;
291 | }
292 | case MotionEvent.ACTION_CANCEL:
293 | mLastPointX = 0;
294 | mLastPointY = 0;
295 | mInController = false;
296 | mInMove = false;
297 | mInDelete = false;
298 | mInReversalHorizontal = false;
299 | mInReversalVertical = false;
300 | break;
301 | case MotionEvent.ACTION_MOVE:
302 | if (mInController) {
303 |
304 | mMatrix.postRotate(rotation(event), mPoints[8], mPoints[9]);
305 | float nowLenght = caculateLength(mPoints[0], mPoints[1]);
306 | float touchLenght = caculateLength(event.getX(), event.getY());
307 | if (FloatMath.sqrt((nowLenght - touchLenght) * (nowLenght - touchLenght)) > 0.0f) {
308 | float scale = touchLenght / nowLenght;
309 | float nowsc = mStickerScaleSize * scale;
310 | if (nowsc >= MIN_SCALE_SIZE && nowsc <= MAX_SCALE_SIZE) {
311 | mMatrix.postScale(scale, scale, mPoints[8], mPoints[9]);
312 | mStickerScaleSize = nowsc;
313 | }
314 | }
315 |
316 | invalidate();
317 | mLastPointX = x;
318 | mLastPointY = y;
319 | break;
320 |
321 | }
322 |
323 | if (mInMove == true) { //拖动的操作
324 | float cX = x - mLastPointX;
325 | float cY = y - mLastPointY;
326 | mInController = false;
327 | //Log.i("MATRIX_OK", "ma_jiaodu:" + a(cX, cY));
328 |
329 | if (FloatMath.sqrt(cX * cX + cY * cY) > 2.0f && canStickerMove(cX, cY)) {
330 | //Log.i("MATRIX_OK", "is true to move");
331 | mMatrix.postTranslate(cX, cY);
332 | postInvalidate();
333 | mLastPointX = x;
334 | mLastPointY = y;
335 | }
336 | break;
337 | }
338 |
339 |
340 | return true;
341 |
342 | }
343 | return true;
344 | }
345 |
346 | private void doDeleteSticker() {
347 | setWaterMark(null);
348 | if (mOnStickerDeleteListener != null) {
349 | mOnStickerDeleteListener.onDelete();
350 | }
351 | }
352 |
353 | //图片水平反转
354 | private void doReversalHorizontal(){
355 | float[] floats = new float[] { -1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 1f };
356 | Matrix tmpMatrix = new Matrix();
357 | tmpMatrix.setValues(floats);
358 | mBitmap = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(),
359 | mBitmap.getHeight(), tmpMatrix, true);
360 | invalidate();
361 | mInReversalHorizontal = false;
362 | }
363 | //图片垂直反转
364 | private void doReversalVertical(){
365 | float[] floats = new float[] { 1f, 0f, 0f, 0f, -1f, 0f, 0f, 0f, 1f };
366 | Matrix tmpMatrix = new Matrix();
367 | tmpMatrix.setValues(floats);
368 | mBitmap = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(),
369 | mBitmap.getHeight(), tmpMatrix, true);
370 | invalidate();
371 | mInReversalVertical = false;
372 | }
373 |
374 |
375 | private boolean canStickerMove(float cx, float cy) {
376 | float px = cx + mPoints[8];
377 | float py = cy + mPoints[9];
378 | if (mViewRect.contains(px, py)) {
379 | return true;
380 | } else {
381 | return false;
382 | }
383 | }
384 |
385 |
386 | private float caculateLength(float x, float y) {
387 | float ex = x - mPoints[8];
388 | float ey = y - mPoints[9];
389 | return FloatMath.sqrt(ex*ex + ey*ey);
390 | }
391 |
392 |
393 | private float rotation(MotionEvent event) {
394 | float originDegree = calculateDegree(mLastPointX, mLastPointY);
395 | float nowDegree = calculateDegree(event.getX(), event.getY());
396 | return nowDegree - originDegree;
397 | }
398 |
399 | private float calculateDegree(float x, float y) {
400 | double delta_x = x - mPoints[8];
401 | double delta_y = y - mPoints[9];
402 | double radians = Math.atan2(delta_y, delta_x);
403 | return (float) Math.toDegrees(radians);
404 | }
405 |
406 | public interface OnStickerDeleteListener {
407 | public void onDelete();
408 | }
409 |
410 | public void setOnStickerDeleteListener(OnStickerDeleteListener listener) {
411 | mOnStickerDeleteListener = listener;
412 | }
413 | }
414 |
--------------------------------------------------------------------------------
/stickerviewLib/src/main/res/drawable-xhdpi/ic_sticker_control.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangmingming/StickerView/17df166f76d18c1f381fe271c78dfd1a3a998086/stickerviewLib/src/main/res/drawable-xhdpi/ic_sticker_control.png
--------------------------------------------------------------------------------
/stickerviewLib/src/main/res/drawable-xhdpi/ic_sticker_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangmingming/StickerView/17df166f76d18c1f381fe271c78dfd1a3a998086/stickerviewLib/src/main/res/drawable-xhdpi/ic_sticker_delete.png
--------------------------------------------------------------------------------
/stickerviewLib/src/main/res/drawable/ic_sticker_reversal_horizontal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangmingming/StickerView/17df166f76d18c1f381fe271c78dfd1a3a998086/stickerviewLib/src/main/res/drawable/ic_sticker_reversal_horizontal.png
--------------------------------------------------------------------------------
/stickerviewLib/src/main/res/drawable/ic_sticker_reversal_vertical.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangmingming/StickerView/17df166f76d18c1f381fe271c78dfd1a3a998086/stickerviewLib/src/main/res/drawable/ic_sticker_reversal_vertical.png
--------------------------------------------------------------------------------
/stickerviewLib/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | StickerView
3 |
4 |
--------------------------------------------------------------------------------
/stickerviewLib/stickerviewLib.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------