├── .gitignore ├── README.md ├── art ├── art_drawer.png ├── art_focus_all.png ├── art_focus_normal.png ├── art_gravity_left.png ├── art_rectangle.png ├── art_toolbar.png └── materialintroviewgif.gif ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── materialintro ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── co │ │ └── mobiwise │ │ └── materialintro │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── co │ │ │ └── mobiwise │ │ │ └── materialintro │ │ │ ├── MaterialIntroConfiguration.java │ │ │ ├── animation │ │ │ ├── AnimationFactory.java │ │ │ ├── AnimationListener.java │ │ │ └── MaterialIntroListener.java │ │ │ ├── prefs │ │ │ └── PreferencesManager.java │ │ │ ├── shape │ │ │ ├── Circle.java │ │ │ ├── Focus.java │ │ │ ├── FocusGravity.java │ │ │ ├── Rect.java │ │ │ ├── Shape.java │ │ │ └── ShapeType.java │ │ │ ├── target │ │ │ ├── Target.java │ │ │ └── ViewTarget.java │ │ │ ├── utils │ │ │ ├── Constants.java │ │ │ └── Utils.java │ │ │ └── view │ │ │ └── MaterialIntroView.java │ └── res │ │ ├── drawable │ │ ├── icon_dotview.png │ │ └── icon_question.png │ │ ├── layout │ │ ├── dotview.xml │ │ └── material_intro_card.xml │ │ └── values │ │ ├── dimens.xml │ │ └── strings.xml │ └── test │ └── java │ └── co │ └── mobiwise │ └── materialintro │ └── ExampleUnitTest.java ├── sample ├── .gitignore ├── Demo_Debug.apk ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── co │ │ └── mobiwise │ │ └── sample │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── co │ │ │ └── mobiwise │ │ │ └── sample │ │ │ ├── MainActivity.java │ │ │ ├── ToolbarMenuItemActivity.java │ │ │ ├── adapter │ │ │ └── RecyclerViewAdapter.java │ │ │ ├── fragment │ │ │ ├── FocusFragment.java │ │ │ ├── GravityFragment.java │ │ │ ├── MainFragment.java │ │ │ └── RecyclerviewFragment.java │ │ │ └── model │ │ │ └── Song.java │ └── res │ │ ├── drawable-v21 │ │ ├── ic_menu_camera.xml │ │ ├── ic_menu_gallery.xml │ │ ├── ic_menu_manage.xml │ │ ├── ic_menu_send.xml │ │ ├── ic_menu_share.xml │ │ └── ic_menu_slideshow.xml │ │ ├── drawable │ │ ├── diamond.png │ │ └── icon_miv.png │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_toolbar.xml │ │ ├── app_bar_main.xml │ │ ├── container.xml │ │ ├── content_main.xml │ │ ├── fragment_focus.xml │ │ ├── fragment_gravity.xml │ │ ├── fragment_recyclerview.xml │ │ ├── list_item_card.xml │ │ ├── nav_header_main.xml │ │ └── toolbar.xml │ │ ├── menu │ │ ├── activity_main_drawer.xml │ │ └── main.xml │ │ ├── mipmap-hdpi │ │ ├── ic_help_outline.png │ │ ├── ic_launcher.png │ │ ├── ic_search.png │ │ └── ic_share_white.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-v21 │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── drawables.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── co │ └── mobiwise │ └── sample │ └── ExampleUnitTest.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Gradle and Android Studio ignores 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | 8 | # IDEA/Android Studio project files, because 9 | # the project can be imported from settings.gradle 10 | .idea 11 | *.iml 12 | 13 | # Built application files 14 | *.apk 15 | *.ap_ 16 | 17 | # Files for the Dalvik VM 18 | *.dex 19 | 20 | # Java class files 21 | *.class 22 | 23 | # Generated files 24 | bin/ 25 | gen/ 26 | 27 | # Gradle files 28 | .gradle/ 29 | build/ 30 | 31 | # Local configuration file (sdk path, etc) 32 | local.properties 33 | 34 | # Proguard folder generated by Eclipse 35 | proguard/ 36 | 37 | # Log Files 38 | *.log 39 | 40 | .idea 41 | *.iml 42 | 43 | # Fabric files 44 | fabric.properties 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MaterialIntroView [Beta] 2 | Material Intro View is a showcase android library. 3 | 4 | We saw this kind of showcase on [Fabulous App](http://www.thefabulous.co/) and we love it. Then decided to create showcase just like it. 5 | 6 | # Screen 7 | 8 | 9 | # Usage 10 | ```java 11 | new MaterialIntroView.Builder(this) 12 | .enableDotAnimation(true) 13 | .enableIcon(false) 14 | .setFocusGravity(FocusGravity.CENTER) 15 | .setFocusType(Focus.MINIMUM) 16 | .setDelayMillis(500) 17 | .enableFadeAnimation(true) 18 | .performClick(true) 19 | .setInfoText("Hi There! Click this card and see what happens.") 20 | .setShapeType(ShapeType.CIRCLE) 21 | .setTarget(view) 22 | .setUsageId("intro_card") //THIS SHOULD BE UNIQUE ID 23 | .show(); 24 | ``` 25 | 26 | # Import 27 | Project build.gradle 28 | ```java 29 | repositories { 30 | maven { 31 | url "https://jitpack.io" 32 | } 33 | } 34 | ``` 35 | 36 | Module build.gradle 37 | ```java 38 | dependencies { 39 | compile 'com.github.iammert:MaterialIntroView:1.6.0' 40 | } 41 | ``` 42 | 43 | # Builder Methods 44 | ```java 45 | .setMaskColor(Color.Blue) 46 | ``` 47 | ```java 48 | .setDelayMillis(3000) //starts after 3 seconds passed 49 | ``` 50 | ```java 51 | .enableFadeAnimation(true) //View will appear/disappear with fade in/out animation 52 | ``` 53 | ```java 54 | //ie. If your button's width has MATCH_PARENT. 55 | //Focus.ALL is not a good option. You can use 56 | //Focus.MINIMUM or Focus.NORMAL. See demos below. 57 | .setFocusType(Focus.MINIMUM) 58 | .setFocusType(Focus.NORMAL) 59 | .setFocusType(Focus.ALL) 60 | ``` 61 | ```java 62 | //ie. You can focus on left of RecyclerView list item. 63 | .setFocusGravity(FocusGravity.LEFT) 64 | .setFocusType(FocusGravity.CENTER) 65 | .setFocusType(FocusGravity.RIGHT) 66 | ``` 67 | ```java 68 | .setTarget(myButton) //Focus on myButton 69 | ``` 70 | ```java 71 | .setTargetPadding(30) //add 30px padding to focus circle 72 | ``` 73 | ```java 74 | .setInfoText("This is info text!") //Setting text will enable info dialog 75 | ``` 76 | ```java 77 | .setTextColor(Color.Black) //Info dialog's text color is set to black 78 | ``` 79 | ```java 80 | .setInfoTextSize(30) //Change text size 81 | ``` 82 | ```java 83 | .setShapeType(ShapeType.CIRCLE) //Change shape of focus area 84 | .setShapeType(ShapeType.RECTANGLE) //Change shape of focus area 85 | ``` 86 | ```java 87 | .setCustomShape(Shape shape) //Use custom shape 88 | ``` 89 | ```java 90 | // Allow this showcase overlay to only show up once. Prevents multiple screens from showing at the same time. 91 | // Useful if you wish to show a tour step in a code that gets called multiple times 92 | .setIdempotent(true) 93 | ``` 94 | ```java 95 | .setUsageId("intro_fab_button") //Store intro view status whether it is learnt or not 96 | ``` 97 | ```java 98 | .enableDotAnimation(true) //Shows dot animation center of focus area 99 | ``` 100 | ```java 101 | .enableIcon(false) //Turn off helper icon, default is true 102 | ``` 103 | ```java 104 | .performClick(true) //Trigger click operation when user click focused area. 105 | ``` 106 | ```java 107 | //If you don't want to perform click automatically 108 | //You can disable perform clik and handle it yourself 109 | .setListener(new MaterialIntroListener() { 110 | @Override 111 | public void onUserClicked(String materialIntroViewId) { 112 | 113 | } 114 | }) 115 | 116 | ``` 117 | # Configuration Method 118 | ```java 119 | //Create global config instance to not write same config to builder 120 | //again and again. 121 | MaterialIntroConfiguration config = new MaterialIntroConfiguration(); 122 | config.setDelayMillis(1000); 123 | config.setFadeAnimationEnabled(true); 124 | ... 125 | .setConfiguration(config) // 126 | ``` 127 | 128 | # Use Custom Shapes 129 | You can use your own highlight shapes if Circle and Rectangle do not work for you. See source for `Circle` and `Rect` for implementation example. 130 | ```java 131 | public class MyShape extends Shape { 132 | // ... your implementation 133 | } 134 | 135 | //... in your app code 136 | 137 | .setCustomShape(MyShape shape) 138 | 139 | ``` 140 | 141 | # Demos 142 | ![Alt text](/art/art_drawer.png?raw=true) 143 | ![Alt text](/art/art_focus_all.png?raw=true) 144 | ![Alt text](/art/art_focus_normal.png?raw=true) 145 | ![Alt text](/art/art_gravity_left.png?raw=true) 146 | ![Alt text](/art/art_rectangle.png?raw=true) 147 | # TODO 148 | 149 | * [ ] Sample app will be more detailed about using library. 150 | * [ ] Sequence for MaterialIntroViews 151 | 152 | # Authors 153 | 154 | [Mert SIMSEK](https://github.com/iammert) 155 | 156 | [Murat Can BUR](https://github.com/muratcanbur) 157 | 158 | 159 | # Docs 160 | [Chinese Doc](http://www.jianshu.com/p/1d2dcbc1e0f2) 161 | 162 | 163 | License 164 | -------- 165 | 166 | 167 | Copyright 2015 Mert Şimşek. 168 | 169 | Licensed under the Apache License, Version 2.0 (the "License"); 170 | you may not use this file except in compliance with the License. 171 | You may obtain a copy of the License at 172 | 173 | http://www.apache.org/licenses/LICENSE-2.0 174 | 175 | Unless required by applicable law or agreed to in writing, software 176 | distributed under the License is distributed on an "AS IS" BASIS, 177 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 178 | See the License for the specific language governing permissions and 179 | limitations under the License. 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | -------------------------------------------------------------------------------- /art/art_drawer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iammert/MaterialIntroView/f7b36b77d691bd0f2b270b378fab8d1aaf8ea273/art/art_drawer.png -------------------------------------------------------------------------------- /art/art_focus_all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iammert/MaterialIntroView/f7b36b77d691bd0f2b270b378fab8d1aaf8ea273/art/art_focus_all.png -------------------------------------------------------------------------------- /art/art_focus_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iammert/MaterialIntroView/f7b36b77d691bd0f2b270b378fab8d1aaf8ea273/art/art_focus_normal.png -------------------------------------------------------------------------------- /art/art_gravity_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iammert/MaterialIntroView/f7b36b77d691bd0f2b270b378fab8d1aaf8ea273/art/art_gravity_left.png -------------------------------------------------------------------------------- /art/art_rectangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iammert/MaterialIntroView/f7b36b77d691bd0f2b270b378fab8d1aaf8ea273/art/art_rectangle.png -------------------------------------------------------------------------------- /art/art_toolbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iammert/MaterialIntroView/f7b36b77d691bd0f2b270b378fab8d1aaf8ea273/art/art_toolbar.png -------------------------------------------------------------------------------- /art/materialintroviewgif.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iammert/MaterialIntroView/f7b36b77d691bd0f2b270b378fab8d1aaf8ea273/art/materialintroviewgif.gif -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.3.3' 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 | maven { 19 | url "https://jitpack.io" 20 | } 21 | maven { 22 | url "https://maven.google.com" 23 | } 24 | } 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /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/iammert/MaterialIntroView/f7b36b77d691bd0f2b270b378fab8d1aaf8ea273/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Oct 17 20:55:44 CEST 2017 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-3.3-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /materialintro/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | *.iml -------------------------------------------------------------------------------- /materialintro/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 26 5 | buildToolsVersion "26.0.2" 6 | 7 | defaultConfig { 8 | minSdkVersion 14 9 | targetSdkVersion 26 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 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | testCompile 'junit:junit:4.12' 25 | compile 'com.android.support:appcompat-v7:26.1.0' 26 | compile 'com.android.support:cardview-v7:26.1.0' 27 | } 28 | -------------------------------------------------------------------------------- /materialintro/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/mertsimsek/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /materialintro/src/androidTest/java/co/mobiwise/materialintro/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.materialintro; 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 | } -------------------------------------------------------------------------------- /materialintro/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /materialintro/src/main/java/co/mobiwise/materialintro/MaterialIntroConfiguration.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.materialintro; 2 | 3 | 4 | import co.mobiwise.materialintro.shape.Focus; 5 | import co.mobiwise.materialintro.shape.FocusGravity; 6 | import co.mobiwise.materialintro.utils.Constants; 7 | 8 | public class MaterialIntroConfiguration { 9 | 10 | private int maskColor; 11 | 12 | private long delayMillis; 13 | 14 | private boolean isFadeAnimationEnabled; 15 | 16 | private Focus focusType; 17 | 18 | private FocusGravity focusGravity; 19 | 20 | private int padding; 21 | 22 | private boolean dismissOnTouch; 23 | 24 | private int colorTextViewInfo; 25 | 26 | private boolean isDotViewEnabled; 27 | 28 | private boolean isImageViewEnabled; 29 | 30 | public MaterialIntroConfiguration() { 31 | maskColor = Constants.DEFAULT_MASK_COLOR; 32 | delayMillis = Constants.DEFAULT_DELAY_MILLIS; 33 | padding = Constants.DEFAULT_TARGET_PADDING; 34 | colorTextViewInfo = Constants.DEFAULT_COLOR_TEXTVIEW_INFO; 35 | focusType = Focus.ALL; 36 | focusGravity = FocusGravity.CENTER; 37 | isFadeAnimationEnabled = false; 38 | dismissOnTouch = false; 39 | isDotViewEnabled = false; 40 | isImageViewEnabled = true; 41 | } 42 | 43 | public int getMaskColor() { 44 | return maskColor; 45 | } 46 | 47 | public void setMaskColor(int maskColor) { 48 | this.maskColor = maskColor; 49 | } 50 | 51 | public long getDelayMillis() { 52 | return delayMillis; 53 | } 54 | 55 | public void setDelayMillis(long delayMillis) { 56 | this.delayMillis = delayMillis; 57 | } 58 | 59 | public boolean isFadeAnimationEnabled() { 60 | return isFadeAnimationEnabled; 61 | } 62 | 63 | public void setFadeAnimationEnabled(boolean fadeAnimationEnabled) { 64 | isFadeAnimationEnabled = fadeAnimationEnabled; 65 | } 66 | 67 | public Focus getFocusType() { 68 | return focusType; 69 | } 70 | 71 | public void setFocusType(Focus focusType) { 72 | this.focusType = focusType; 73 | } 74 | 75 | public FocusGravity getFocusGravity() { 76 | return focusGravity; 77 | } 78 | 79 | public void setFocusGravity(FocusGravity focusGravity) { 80 | this.focusGravity = focusGravity; 81 | } 82 | 83 | public int getPadding() { 84 | return padding; 85 | } 86 | 87 | public void setPadding(int padding) { 88 | this.padding = padding; 89 | } 90 | 91 | public boolean isDismissOnTouch() { 92 | return dismissOnTouch; 93 | } 94 | 95 | public void setDismissOnTouch(boolean dismissOnTouch) { 96 | this.dismissOnTouch = dismissOnTouch; 97 | } 98 | 99 | public int getColorTextViewInfo() { 100 | return colorTextViewInfo; 101 | } 102 | 103 | public void setColorTextViewInfo(int colorTextViewInfo) { 104 | this.colorTextViewInfo = colorTextViewInfo; 105 | } 106 | 107 | public boolean isDotViewEnabled() { 108 | return isDotViewEnabled; 109 | } 110 | 111 | public boolean isImageViewEnabled(){ 112 | return isImageViewEnabled; 113 | } 114 | 115 | public void setDotViewEnabled(boolean dotViewEnabled) { 116 | isDotViewEnabled = dotViewEnabled; 117 | } 118 | } -------------------------------------------------------------------------------- /materialintro/src/main/java/co/mobiwise/materialintro/animation/AnimationFactory.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.materialintro.animation; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorSet; 5 | import android.animation.ObjectAnimator; 6 | import android.animation.ValueAnimator; 7 | import android.view.View; 8 | 9 | /** 10 | * Created by mertsimsek on 25/01/16. 11 | */ 12 | public class AnimationFactory { 13 | 14 | /** 15 | * MaterialIntroView will appear on screen with 16 | * fade in animation. Notifies onAnimationStartListener 17 | * when fade in animation is about to start. 18 | * 19 | * @param view 20 | * @param duration 21 | * @param onAnimationStartListener 22 | */ 23 | public static void animateFadeIn(View view, long duration, final AnimationListener.OnAnimationStartListener onAnimationStartListener) { 24 | ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f); 25 | objectAnimator.setDuration(duration); 26 | objectAnimator.addListener(new Animator.AnimatorListener() { 27 | @Override 28 | public void onAnimationStart(Animator animation) { 29 | if (onAnimationStartListener != null) 30 | onAnimationStartListener.onAnimationStart(); 31 | } 32 | 33 | @Override 34 | public void onAnimationEnd(Animator animation) { 35 | 36 | } 37 | 38 | @Override 39 | public void onAnimationCancel(Animator animation) { 40 | 41 | } 42 | 43 | @Override 44 | public void onAnimationRepeat(Animator animation) { 45 | 46 | } 47 | }); 48 | objectAnimator.start(); 49 | } 50 | 51 | /** 52 | * MaterialIntroView will disappear from screen with 53 | * fade out animation. Notifies onAnimationEndListener 54 | * when fade out animation is ended. 55 | * 56 | * @param view 57 | * @param duration 58 | * @param onAnimationEndListener 59 | */ 60 | public static void animateFadeOut(View view, long duration, final AnimationListener.OnAnimationEndListener onAnimationEndListener) { 61 | ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, "alpha", 1, 0); 62 | objectAnimator.setDuration(duration); 63 | objectAnimator.addListener(new Animator.AnimatorListener() { 64 | @Override 65 | public void onAnimationStart(Animator animation) { 66 | 67 | } 68 | 69 | @Override 70 | public void onAnimationEnd(Animator animation) { 71 | if (onAnimationEndListener != null) 72 | onAnimationEndListener.onAnimationEnd(); 73 | } 74 | 75 | @Override 76 | public void onAnimationCancel(Animator animation) { 77 | 78 | } 79 | 80 | @Override 81 | public void onAnimationRepeat(Animator animation) { 82 | 83 | } 84 | }); 85 | objectAnimator.start(); 86 | } 87 | 88 | public static void performAnimation(View view) { 89 | 90 | AnimatorSet animatorSet = new AnimatorSet(); 91 | 92 | ValueAnimator scaleX = ObjectAnimator.ofFloat(view, View.SCALE_X, 0.6f); 93 | scaleX.setRepeatCount(ValueAnimator.INFINITE); 94 | scaleX.setRepeatMode(ValueAnimator.REVERSE); 95 | scaleX.setDuration(1000); 96 | 97 | ValueAnimator scaleY = ObjectAnimator.ofFloat(view, View.SCALE_Y, 0.6f); 98 | scaleY.setRepeatCount(ValueAnimator.INFINITE); 99 | scaleY.setRepeatMode(ValueAnimator.REVERSE); 100 | scaleY.setDuration(1000); 101 | 102 | animatorSet.playTogether(scaleX, scaleY); 103 | animatorSet.start(); 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /materialintro/src/main/java/co/mobiwise/materialintro/animation/AnimationListener.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.materialintro.animation; 2 | 3 | /** 4 | * Created by mertsimsek on 25/01/16. 5 | */ 6 | public interface AnimationListener { 7 | 8 | /** 9 | * We need to make MaterialIntroView visible 10 | * before fade in animation starts 11 | */ 12 | interface OnAnimationStartListener{ 13 | void onAnimationStart(); 14 | } 15 | 16 | /** 17 | * We need to make MaterialIntroView invisible 18 | * after fade out animation ends. 19 | */ 20 | interface OnAnimationEndListener{ 21 | void onAnimationEnd(); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /materialintro/src/main/java/co/mobiwise/materialintro/animation/MaterialIntroListener.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.materialintro.animation; 2 | 3 | /** 4 | * Created by mertsimsek on 30/01/16. 5 | */ 6 | public interface MaterialIntroListener { 7 | 8 | void onUserClicked(String materialIntroViewId); 9 | } 10 | -------------------------------------------------------------------------------- /materialintro/src/main/java/co/mobiwise/materialintro/prefs/PreferencesManager.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.materialintro.prefs; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | 6 | /** 7 | * Created by mertsimsek on 29/01/16. 8 | */ 9 | public class PreferencesManager { 10 | 11 | private static final String PREFERENCES_NAME = "material_intro_preferences"; 12 | 13 | private SharedPreferences sharedPreferences; 14 | 15 | public PreferencesManager(Context context) { 16 | sharedPreferences = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE); 17 | } 18 | 19 | public boolean isDisplayed(String id){ 20 | return sharedPreferences.getBoolean(id, false); 21 | } 22 | 23 | public void setDisplayed(String id){ 24 | sharedPreferences.edit().putBoolean(id,true).apply(); 25 | } 26 | 27 | public void reset(String id){ 28 | sharedPreferences.edit().putBoolean(id, false).apply(); 29 | } 30 | 31 | public void resetAll(){ 32 | sharedPreferences.edit().clear().apply(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /materialintro/src/main/java/co/mobiwise/materialintro/shape/Circle.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.materialintro.shape; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Paint; 5 | import android.graphics.Point; 6 | 7 | import co.mobiwise.materialintro.target.Target; 8 | 9 | /** 10 | * Created by mertsimsek on 25/01/16. 11 | */ 12 | public class Circle extends Shape { 13 | 14 | private int radius; 15 | 16 | private Point circlePoint; 17 | 18 | public Circle(Target target, Focus focus, FocusGravity focusGravity, int padding) { 19 | super(target, focus, focusGravity, padding); 20 | circlePoint = getFocusPoint(); 21 | calculateRadius(padding); 22 | } 23 | 24 | @Override 25 | public void draw(Canvas canvas, Paint eraser, int padding){ 26 | calculateRadius(padding); 27 | circlePoint = getFocusPoint(); 28 | canvas.drawCircle(circlePoint.x, circlePoint.y, radius, eraser); 29 | } 30 | 31 | @Override 32 | public void reCalculateAll(){ 33 | calculateRadius(padding); 34 | circlePoint = getFocusPoint(); 35 | } 36 | 37 | private void calculateRadius(int padding){ 38 | int side; 39 | 40 | if(focus == Focus.MINIMUM) 41 | side = Math.min(target.getRect().width() / 2, target.getRect().height() / 2); 42 | else if(focus == Focus.ALL) 43 | side = Math.max(target.getRect().width() / 2, target.getRect().height() / 2); 44 | else{ 45 | int minSide = Math.min(target.getRect().width() / 2, target.getRect().height() / 2); 46 | int maxSide = Math.max(target.getRect().width() / 2, target.getRect().height() / 2); 47 | side = (minSide + maxSide) / 2; 48 | } 49 | 50 | radius = side + padding; 51 | } 52 | 53 | private int getRadius(){ 54 | return radius; 55 | } 56 | 57 | @Override 58 | public Point getPoint(){ 59 | return circlePoint; 60 | } 61 | 62 | @Override 63 | public int getHeight() { 64 | return 2 * getRadius(); 65 | } 66 | 67 | @Override 68 | public boolean isTouchOnFocus(double x, double y) { 69 | int xV = getPoint().x; 70 | int yV = getPoint().y; 71 | 72 | double dx = Math.pow(x - xV, 2); 73 | double dy = Math.pow(y - yV, 2); 74 | return (dx + dy) <= Math.pow(radius, 2); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /materialintro/src/main/java/co/mobiwise/materialintro/shape/Focus.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.materialintro.shape; 2 | 3 | /** 4 | * Created by mertsimsek on 25/01/16. 5 | */ 6 | public enum Focus { 7 | /** 8 | * Focus on target with circle 9 | * These enum decides circle radius. 10 | */ 11 | MINIMUM, NORMAL, ALL 12 | } 13 | -------------------------------------------------------------------------------- /materialintro/src/main/java/co/mobiwise/materialintro/shape/FocusGravity.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.materialintro.shape; 2 | 3 | /** 4 | * Created by mertsimsek on 26/01/16. 5 | */ 6 | public enum FocusGravity { 7 | 8 | /** 9 | * Gravity for focus circle 10 | * ie. We may want to focus on 11 | * left of recyclerview item 12 | */ 13 | LEFT, CENTER, RIGHT 14 | } 15 | -------------------------------------------------------------------------------- /materialintro/src/main/java/co/mobiwise/materialintro/shape/Rect.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.materialintro.shape; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Paint; 5 | import android.graphics.Point; 6 | import android.graphics.RectF; 7 | 8 | import co.mobiwise.materialintro.target.Target; 9 | 10 | /** 11 | * Created by mertsimsek on 25/01/16. 12 | */ 13 | public class Rect extends Shape { 14 | 15 | RectF adjustedRect; 16 | 17 | public Rect(Target target) { 18 | super(target); 19 | calculateAdjustedRect(); 20 | } 21 | 22 | public Rect(Target target, Focus focus) { 23 | super(target, focus); 24 | calculateAdjustedRect(); 25 | } 26 | 27 | public Rect(Target target, Focus focus, FocusGravity focusGravity, int padding) { 28 | super(target, focus, focusGravity, padding); 29 | calculateAdjustedRect(); 30 | } 31 | 32 | @Override 33 | public void draw(Canvas canvas, Paint eraser, int padding) { 34 | canvas.drawRoundRect(adjustedRect, padding, padding, eraser); 35 | } 36 | 37 | private void calculateAdjustedRect() { 38 | RectF rect = new RectF(); 39 | rect.set(target.getRect()); 40 | 41 | rect.left -= padding; 42 | rect.top -= padding; 43 | rect.right += padding; 44 | rect.bottom += padding; 45 | 46 | adjustedRect = rect; 47 | } 48 | 49 | @Override 50 | public void reCalculateAll(){ 51 | calculateAdjustedRect(); 52 | } 53 | 54 | @Override 55 | public Point getPoint(){ 56 | return target.getPoint(); 57 | } 58 | 59 | @Override 60 | public int getHeight() { 61 | return (int) adjustedRect.height(); 62 | } 63 | 64 | @Override 65 | public boolean isTouchOnFocus(double x, double y) { 66 | return adjustedRect.contains((float) x, (float) y); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /materialintro/src/main/java/co/mobiwise/materialintro/shape/Shape.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.materialintro.shape; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Paint; 5 | import android.graphics.Point; 6 | 7 | import co.mobiwise.materialintro.target.Target; 8 | import co.mobiwise.materialintro.utils.Constants; 9 | 10 | /** 11 | * Created by yuchen on 3/17/16. 12 | */ 13 | public abstract class Shape { 14 | 15 | protected Target target; 16 | 17 | protected Focus focus; 18 | 19 | protected FocusGravity focusGravity; 20 | 21 | protected int padding; 22 | 23 | public Shape(Target target) { 24 | this(target, Focus.MINIMUM); 25 | } 26 | 27 | public Shape(Target target,Focus focus) { 28 | this(target, focus, FocusGravity.CENTER, Constants.DEFAULT_TARGET_PADDING); 29 | } 30 | 31 | public Shape(Target target, Focus focus, FocusGravity focusGravity, int padding) { 32 | this.target = target; 33 | this.focus = focus; 34 | this.focusGravity = focusGravity; 35 | this.padding = padding; 36 | } 37 | 38 | public abstract void draw(Canvas canvas, Paint eraser, int padding); 39 | 40 | protected Point getFocusPoint(){ 41 | if(focusGravity == FocusGravity.LEFT){ 42 | int xLeft = target.getRect().left + (target.getPoint().x - target.getRect().left) / 2; 43 | return new Point(xLeft, target.getPoint().y); 44 | } 45 | else if(focusGravity == FocusGravity.RIGHT){ 46 | int xRight = target.getPoint().x + (target.getRect().right - target.getPoint().x) / 2; 47 | return new Point(xRight, target.getPoint().y); 48 | } 49 | else 50 | return target.getPoint(); 51 | } 52 | 53 | public abstract void reCalculateAll(); 54 | 55 | public abstract Point getPoint(); 56 | 57 | public abstract int getHeight(); 58 | 59 | /** 60 | * Determines if a click is on the shape 61 | * @param x x-axis location of click 62 | * @param y y-axis location of click 63 | * @return true if click is inside shape 64 | */ 65 | public abstract boolean isTouchOnFocus(double x, double t); 66 | } 67 | -------------------------------------------------------------------------------- /materialintro/src/main/java/co/mobiwise/materialintro/shape/ShapeType.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.materialintro.shape; 2 | 3 | /** 4 | * Created by yuchen on 3/17/16. 5 | */ 6 | public enum ShapeType { 7 | /** 8 | * Allows the target area to be highlighted by either a circle or rectangle 9 | */ 10 | CIRCLE, RECTANGLE 11 | } 12 | -------------------------------------------------------------------------------- /materialintro/src/main/java/co/mobiwise/materialintro/target/Target.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.materialintro.target; 2 | 3 | import android.graphics.Point; 4 | import android.graphics.Rect; 5 | import android.view.View; 6 | 7 | /** 8 | * Created by mertsimsek on 25/01/16. 9 | */ 10 | public interface Target { 11 | /** 12 | * Returns center point of target. 13 | * We can get x and y coordinates using 14 | * point object 15 | * @return 16 | */ 17 | Point getPoint(); 18 | 19 | /** 20 | * Returns Rectangle points of target view 21 | * @return 22 | */ 23 | Rect getRect(); 24 | 25 | /** 26 | * return target view 27 | * @return 28 | */ 29 | View getView(); 30 | } 31 | -------------------------------------------------------------------------------- /materialintro/src/main/java/co/mobiwise/materialintro/target/ViewTarget.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.materialintro.target; 2 | 3 | import android.graphics.Point; 4 | import android.graphics.Rect; 5 | import android.view.View; 6 | 7 | /** 8 | * Created by mertsimsek on 25/01/16. 9 | */ 10 | public class ViewTarget implements Target{ 11 | 12 | private View view; 13 | 14 | public ViewTarget(View view) { 15 | this.view = view; 16 | } 17 | 18 | @Override 19 | public Point getPoint() { 20 | 21 | int[] location = new int[2]; 22 | view.getLocationInWindow(location); 23 | return new Point(location[0] + (view.getWidth() / 2), location[1] + (view.getHeight() / 2)); 24 | } 25 | 26 | @Override 27 | public Rect getRect() { 28 | int[] location = new int[2]; 29 | view.getLocationInWindow(location); 30 | return new Rect( 31 | location[0], 32 | location[1], 33 | location[0] + view.getWidth(), 34 | location[1] + view.getHeight() 35 | ); 36 | } 37 | 38 | @Override 39 | public View getView() { 40 | return view; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /materialintro/src/main/java/co/mobiwise/materialintro/utils/Constants.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.materialintro.utils; 2 | 3 | /** 4 | * Created by mertsimsek on 24/01/16. 5 | */ 6 | public class Constants { 7 | 8 | public static int DEFAULT_MASK_COLOR = 0x70000000; 9 | 10 | public static long DEFAULT_DELAY_MILLIS = 0; 11 | 12 | public static long DEFAULT_FADE_DURATION = 700; 13 | 14 | public static int DEFAULT_TARGET_PADDING = 10; 15 | 16 | public static int DEFAULT_COLOR_TEXTVIEW_INFO = 0xFF000000; 17 | 18 | public static int DEFAULT_DOT_SIZE = 55; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /materialintro/src/main/java/co/mobiwise/materialintro/utils/Utils.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.materialintro.utils; 2 | 3 | import android.content.res.Resources; 4 | 5 | /** 6 | * Created by mertsimsek on 29/01/16. 7 | */ 8 | public class Utils { 9 | 10 | public static int pxToDp(int px){ 11 | return (int) (px / Resources.getSystem().getDisplayMetrics().density); 12 | } 13 | 14 | public static int dpToPx(int dp){ 15 | return (int) (dp * Resources.getSystem().getDisplayMetrics().density); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /materialintro/src/main/java/co/mobiwise/materialintro/view/MaterialIntroView.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.materialintro.view; 2 | 3 | import android.annotation.TargetApi; 4 | import android.app.Activity; 5 | import android.content.Context; 6 | import android.graphics.Bitmap; 7 | import android.graphics.Canvas; 8 | import android.graphics.Color; 9 | import android.graphics.Paint; 10 | import android.graphics.PorterDuff; 11 | import android.graphics.PorterDuffXfermode; 12 | import android.os.Build; 13 | import android.os.Handler; 14 | import android.util.AttributeSet; 15 | import android.util.TypedValue; 16 | import android.view.Gravity; 17 | import android.view.LayoutInflater; 18 | import android.view.MotionEvent; 19 | import android.view.View; 20 | import android.view.ViewGroup; 21 | import android.view.ViewTreeObserver; 22 | import android.widget.ImageView; 23 | import android.widget.RelativeLayout; 24 | import android.widget.TextView; 25 | 26 | import co.mobiwise.materialintro.MaterialIntroConfiguration; 27 | import co.mobiwise.materialintro.R; 28 | import co.mobiwise.materialintro.animation.AnimationFactory; 29 | import co.mobiwise.materialintro.animation.AnimationListener; 30 | import co.mobiwise.materialintro.animation.MaterialIntroListener; 31 | import co.mobiwise.materialintro.prefs.PreferencesManager; 32 | import co.mobiwise.materialintro.shape.Circle; 33 | import co.mobiwise.materialintro.shape.Focus; 34 | import co.mobiwise.materialintro.shape.FocusGravity; 35 | import co.mobiwise.materialintro.shape.Rect; 36 | import co.mobiwise.materialintro.shape.Shape; 37 | import co.mobiwise.materialintro.shape.ShapeType; 38 | import co.mobiwise.materialintro.target.Target; 39 | import co.mobiwise.materialintro.target.ViewTarget; 40 | import co.mobiwise.materialintro.utils.Constants; 41 | import co.mobiwise.materialintro.utils.Utils; 42 | 43 | /** 44 | * Created by mertsimsek on 22/01/16. 45 | */ 46 | public class MaterialIntroView extends RelativeLayout { 47 | 48 | /** 49 | * Mask color 50 | */ 51 | private int maskColor; 52 | 53 | /** 54 | * MaterialIntroView will start 55 | * showing after delayMillis seconds 56 | * passed 57 | */ 58 | private long delayMillis; 59 | 60 | /** 61 | * We don't draw MaterialIntroView 62 | * until isReady field set to true 63 | */ 64 | private boolean isReady; 65 | 66 | /** 67 | * Show/Dismiss MaterialIntroView 68 | * with fade in/out animation if 69 | * this is enabled. 70 | */ 71 | private boolean isFadeAnimationEnabled; 72 | 73 | /** 74 | * Animation duration 75 | */ 76 | private long fadeAnimationDuration; 77 | 78 | /** 79 | * targetShape focus on target 80 | * and clear circle to focus 81 | */ 82 | private Shape targetShape; 83 | 84 | /** 85 | * Focus Type 86 | */ 87 | private Focus focusType; 88 | 89 | /** 90 | * FocusGravity type 91 | */ 92 | private FocusGravity focusGravity; 93 | 94 | /** 95 | * Target View 96 | */ 97 | private Target targetView; 98 | 99 | /** 100 | * Eraser 101 | */ 102 | private Paint eraser; 103 | 104 | /** 105 | * Handler will be used to 106 | * delay MaterialIntroView 107 | */ 108 | private Handler handler; 109 | 110 | /** 111 | * All views will be drawn to 112 | * this bitmap and canvas then 113 | * bitmap will be drawn to canvas 114 | */ 115 | private Bitmap bitmap; 116 | private Canvas canvas; 117 | 118 | /** 119 | * Circle padding 120 | */ 121 | private int padding; 122 | 123 | /** 124 | * Layout width/height 125 | */ 126 | private int width; 127 | private int height; 128 | 129 | /** 130 | * Dismiss on touch any position 131 | */ 132 | private boolean dismissOnTouch; 133 | 134 | /** 135 | * Info dialog view 136 | */ 137 | private View infoView; 138 | 139 | /** 140 | * Info Dialog Text 141 | */ 142 | private TextView textViewInfo; 143 | 144 | /** 145 | * Info dialog text color 146 | */ 147 | private int colorTextViewInfo; 148 | 149 | /** 150 | * Info dialog will be shown 151 | * If this value true 152 | */ 153 | private boolean isInfoEnabled; 154 | 155 | /** 156 | * Dot view will appear center of 157 | * cleared target area 158 | */ 159 | private View dotView; 160 | 161 | /** 162 | * Dot View will be shown if 163 | * this is true 164 | */ 165 | private boolean isDotViewEnabled; 166 | 167 | /** 168 | * Info Dialog Icon 169 | */ 170 | private ImageView imageViewIcon; 171 | 172 | /** 173 | * Image View will be shown if 174 | * this is true 175 | */ 176 | private boolean isImageViewEnabled; 177 | 178 | /** 179 | * Save/Retrieve status of MaterialIntroView 180 | * If Intro is already learnt then don't show 181 | * it again. 182 | */ 183 | private PreferencesManager preferencesManager; 184 | 185 | /** 186 | * Check using this Id whether user learned 187 | * or not. 188 | */ 189 | private String materialIntroViewId; 190 | 191 | /** 192 | * When layout completed, we set this true 193 | * Otherwise onGlobalLayoutListener stuck on loop. 194 | */ 195 | private boolean isLayoutCompleted; 196 | 197 | /** 198 | * Notify user when MaterialIntroView is dismissed 199 | */ 200 | private MaterialIntroListener materialIntroListener; 201 | 202 | /** 203 | * Perform click operation to target 204 | * if this is true 205 | */ 206 | private boolean isPerformClick; 207 | 208 | /** 209 | * Disallow this MaterialIntroView from showing up more than once at a time 210 | */ 211 | private boolean isIdempotent; 212 | 213 | /** 214 | * Shape of target 215 | */ 216 | private ShapeType shapeType; 217 | 218 | /** 219 | * Use custom shape 220 | */ 221 | private boolean usesCustomShape = false; 222 | 223 | public MaterialIntroView(Context context) { 224 | super(context); 225 | init(context); 226 | } 227 | 228 | public MaterialIntroView(Context context, AttributeSet attrs) { 229 | super(context, attrs); 230 | init(context); 231 | } 232 | 233 | public MaterialIntroView(Context context, AttributeSet attrs, int defStyleAttr) { 234 | super(context, attrs, defStyleAttr); 235 | init(context); 236 | } 237 | 238 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 239 | public MaterialIntroView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 240 | super(context, attrs, defStyleAttr, defStyleRes); 241 | init(context); 242 | } 243 | 244 | private void init(Context context) { 245 | setWillNotDraw(false); 246 | setVisibility(INVISIBLE); 247 | 248 | /** 249 | * set default values 250 | */ 251 | maskColor = Constants.DEFAULT_MASK_COLOR; 252 | delayMillis = Constants.DEFAULT_DELAY_MILLIS; 253 | fadeAnimationDuration = Constants.DEFAULT_FADE_DURATION; 254 | padding = Constants.DEFAULT_TARGET_PADDING; 255 | colorTextViewInfo = Constants.DEFAULT_COLOR_TEXTVIEW_INFO; 256 | focusType = Focus.ALL; 257 | focusGravity = FocusGravity.CENTER; 258 | shapeType = ShapeType.CIRCLE; 259 | isReady = false; 260 | isFadeAnimationEnabled = true; 261 | dismissOnTouch = false; 262 | isLayoutCompleted = false; 263 | isInfoEnabled = false; 264 | isDotViewEnabled = false; 265 | isPerformClick = false; 266 | isImageViewEnabled = true; 267 | isIdempotent = false; 268 | 269 | /** 270 | * initialize objects 271 | */ 272 | handler = new Handler(); 273 | 274 | preferencesManager = new PreferencesManager(context); 275 | 276 | eraser = new Paint(); 277 | eraser.setColor(0xFFFFFFFF); 278 | eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); 279 | eraser.setFlags(Paint.ANTI_ALIAS_FLAG); 280 | 281 | View layoutInfo = LayoutInflater.from(getContext()).inflate(R.layout.material_intro_card, null); 282 | 283 | infoView = layoutInfo.findViewById(R.id.info_layout); 284 | textViewInfo = (TextView) layoutInfo.findViewById(R.id.textview_info); 285 | textViewInfo.setTextColor(colorTextViewInfo); 286 | imageViewIcon = (ImageView) layoutInfo.findViewById(R.id.imageview_icon); 287 | 288 | dotView = LayoutInflater.from(getContext()).inflate(R.layout.dotview, null); 289 | dotView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); 290 | 291 | getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 292 | @Override 293 | public void onGlobalLayout() { 294 | targetShape.reCalculateAll(); 295 | if (targetShape != null && targetShape.getPoint().y != 0 && !isLayoutCompleted) { 296 | if (isInfoEnabled) 297 | setInfoLayout(); 298 | if(isDotViewEnabled) 299 | setDotViewLayout(); 300 | removeOnGlobalLayoutListener(MaterialIntroView.this, this); 301 | } 302 | } 303 | }); 304 | 305 | } 306 | 307 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 308 | public static void removeOnGlobalLayoutListener(View v, ViewTreeObserver.OnGlobalLayoutListener listener){ 309 | if (Build.VERSION.SDK_INT < 16) { 310 | v.getViewTreeObserver().removeGlobalOnLayoutListener(listener); 311 | } else { 312 | v.getViewTreeObserver().removeOnGlobalLayoutListener(listener); 313 | } 314 | } 315 | 316 | @Override 317 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 318 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 319 | 320 | width = getMeasuredWidth(); 321 | height = getMeasuredHeight(); 322 | } 323 | 324 | @Override 325 | protected void onDraw(Canvas canvas) { 326 | super.onDraw(canvas); 327 | 328 | if (!isReady) return; 329 | 330 | if (bitmap == null || canvas == null) { 331 | if (bitmap != null) bitmap.recycle(); 332 | 333 | bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 334 | this.canvas = new Canvas(bitmap); 335 | } 336 | 337 | /** 338 | * Draw mask 339 | */ 340 | this.canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); 341 | this.canvas.drawColor(maskColor); 342 | 343 | /** 344 | * Clear focus area 345 | */ 346 | targetShape.draw(this.canvas, eraser, padding); 347 | 348 | canvas.drawBitmap(bitmap, 0, 0, null); 349 | } 350 | 351 | /** 352 | * Perform click operation when user 353 | * touches on target circle. 354 | * 355 | * @param event 356 | * @return 357 | */ 358 | @Override 359 | public boolean onTouchEvent(MotionEvent event) { 360 | float xT = event.getX(); 361 | float yT = event.getY(); 362 | 363 | boolean isTouchOnFocus = targetShape.isTouchOnFocus(xT, yT); 364 | 365 | switch (event.getAction()) { 366 | case MotionEvent.ACTION_DOWN: 367 | 368 | if (isTouchOnFocus && isPerformClick) { 369 | targetView.getView().setPressed(true); 370 | targetView.getView().invalidate(); 371 | } 372 | 373 | return true; 374 | case MotionEvent.ACTION_UP: 375 | 376 | if (isTouchOnFocus || dismissOnTouch) 377 | dismiss(); 378 | 379 | if (isTouchOnFocus && isPerformClick) { 380 | targetView.getView().performClick(); 381 | targetView.getView().setPressed(true); 382 | targetView.getView().invalidate(); 383 | targetView.getView().setPressed(false); 384 | targetView.getView().invalidate(); 385 | } 386 | 387 | return true; 388 | default: 389 | break; 390 | } 391 | 392 | return super.onTouchEvent(event); 393 | } 394 | 395 | /** 396 | * Shows material view with fade in 397 | * animation 398 | * 399 | * @param activity 400 | */ 401 | private void show(Activity activity) { 402 | 403 | if (preferencesManager.isDisplayed(materialIntroViewId)) 404 | return; 405 | 406 | ((ViewGroup) activity.getWindow().getDecorView()).addView(this); 407 | 408 | setReady(true); 409 | 410 | handler.postDelayed(new Runnable() { 411 | @Override 412 | public void run() { 413 | if (isFadeAnimationEnabled) 414 | AnimationFactory.animateFadeIn(MaterialIntroView.this, fadeAnimationDuration, new AnimationListener.OnAnimationStartListener() { 415 | @Override 416 | public void onAnimationStart() { 417 | setVisibility(VISIBLE); 418 | } 419 | }); 420 | else 421 | setVisibility(VISIBLE); 422 | } 423 | }, delayMillis); 424 | 425 | if(isIdempotent) { 426 | preferencesManager.setDisplayed(materialIntroViewId); 427 | } 428 | } 429 | 430 | /** 431 | * Dismiss Material Intro View 432 | */ 433 | public void dismiss() { 434 | if(!isIdempotent) { 435 | preferencesManager.setDisplayed(materialIntroViewId); 436 | } 437 | 438 | AnimationFactory.animateFadeOut(this, fadeAnimationDuration, new AnimationListener.OnAnimationEndListener() { 439 | @Override 440 | public void onAnimationEnd() { 441 | setVisibility(GONE); 442 | removeMaterialView(); 443 | 444 | if (materialIntroListener != null) 445 | materialIntroListener.onUserClicked(materialIntroViewId); 446 | } 447 | }); 448 | } 449 | 450 | private void removeMaterialView(){ 451 | if(getParent() != null ) 452 | ((ViewGroup) getParent()).removeView(this); 453 | } 454 | 455 | /** 456 | * locate info card view above/below the 457 | * circle. If circle's Y coordiante is bigger than 458 | * Y coordinate of root view, then locate cardview 459 | * above the circle. Otherwise locate below. 460 | */ 461 | private void setInfoLayout() { 462 | 463 | handler.post(new Runnable() { 464 | @Override 465 | public void run() { 466 | isLayoutCompleted = true; 467 | 468 | if (infoView.getParent() != null) 469 | ((ViewGroup) infoView.getParent()).removeView(infoView); 470 | 471 | RelativeLayout.LayoutParams infoDialogParams = new RelativeLayout.LayoutParams( 472 | ViewGroup.LayoutParams.MATCH_PARENT, 473 | ViewGroup.LayoutParams.FILL_PARENT); 474 | 475 | if (targetShape.getPoint().y < height / 2) { 476 | ((RelativeLayout) infoView).setGravity(Gravity.TOP); 477 | infoDialogParams.setMargins( 478 | 0, 479 | targetShape.getPoint().y + targetShape.getHeight() / 2, 480 | 0, 481 | 0); 482 | } else { 483 | ((RelativeLayout) infoView).setGravity(Gravity.BOTTOM); 484 | infoDialogParams.setMargins( 485 | 0, 486 | 0, 487 | 0, 488 | height - (targetShape.getPoint().y + targetShape.getHeight() / 2) + 2 * targetShape.getHeight() / 2); 489 | } 490 | 491 | infoView.setLayoutParams(infoDialogParams); 492 | infoView.postInvalidate(); 493 | 494 | addView(infoView); 495 | 496 | if (!isImageViewEnabled){ 497 | imageViewIcon.setVisibility(GONE); 498 | } 499 | 500 | infoView.setVisibility(VISIBLE); 501 | } 502 | }); 503 | } 504 | 505 | private void setDotViewLayout() { 506 | 507 | handler.post(new Runnable() { 508 | @Override 509 | public void run() { 510 | 511 | if (dotView.getParent() != null) 512 | ((ViewGroup) dotView.getParent()).removeView(dotView); 513 | 514 | RelativeLayout.LayoutParams dotViewLayoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); 515 | dotViewLayoutParams.height = Utils.dpToPx(Constants.DEFAULT_DOT_SIZE); 516 | dotViewLayoutParams.width = Utils.dpToPx(Constants.DEFAULT_DOT_SIZE); 517 | dotViewLayoutParams.setMargins( 518 | targetShape.getPoint().x - (dotViewLayoutParams.width / 2), 519 | targetShape.getPoint().y - (dotViewLayoutParams.height / 2), 520 | 0, 521 | 0); 522 | dotView.setLayoutParams(dotViewLayoutParams); 523 | dotView.postInvalidate(); 524 | addView(dotView); 525 | 526 | dotView.setVisibility(VISIBLE); 527 | AnimationFactory.performAnimation(dotView); 528 | } 529 | }); 530 | } 531 | 532 | /** 533 | * SETTERS 534 | */ 535 | 536 | private void setMaskColor(int maskColor) { 537 | this.maskColor = maskColor; 538 | } 539 | 540 | private void setDelay(int delayMillis) { 541 | this.delayMillis = delayMillis; 542 | } 543 | 544 | private void enableFadeAnimation(boolean isFadeAnimationEnabled) { 545 | this.isFadeAnimationEnabled = isFadeAnimationEnabled; 546 | } 547 | 548 | private void setShapeType(ShapeType shape) { 549 | this.shapeType = shape; 550 | } 551 | 552 | private void setReady(boolean isReady) { 553 | this.isReady = isReady; 554 | } 555 | 556 | private void setTarget(Target target) { 557 | targetView = target; 558 | } 559 | 560 | private void setFocusType(Focus focusType) { 561 | this.focusType = focusType; 562 | } 563 | 564 | private void setShape(Shape shape) { 565 | this.targetShape = shape; 566 | } 567 | 568 | private void setPadding(int padding) { 569 | this.padding = padding; 570 | } 571 | 572 | private void setDismissOnTouch(boolean dismissOnTouch) { 573 | this.dismissOnTouch = dismissOnTouch; 574 | } 575 | 576 | private void setFocusGravity(FocusGravity focusGravity) { 577 | this.focusGravity = focusGravity; 578 | } 579 | 580 | private void setColorTextViewInfo(int colorTextViewInfo) { 581 | this.colorTextViewInfo = colorTextViewInfo; 582 | textViewInfo.setTextColor(this.colorTextViewInfo); 583 | } 584 | 585 | private void setTextViewInfo(CharSequence textViewInfo) { 586 | this.textViewInfo.setText(textViewInfo); 587 | } 588 | 589 | private void setTextViewInfoSize(int textViewInfoSize) { 590 | this.textViewInfo.setTextSize(TypedValue.COMPLEX_UNIT_SP, textViewInfoSize); 591 | } 592 | 593 | private void enableInfoDialog(boolean isInfoEnabled) { 594 | this.isInfoEnabled = isInfoEnabled; 595 | } 596 | 597 | private void enableImageViewIcon(boolean isImageViewEnabled){ 598 | this.isImageViewEnabled = isImageViewEnabled; 599 | } 600 | 601 | private void setIdempotent(boolean idempotent){ 602 | this.isIdempotent = idempotent; 603 | } 604 | 605 | private void enableDotView(boolean isDotViewEnabled){ 606 | this.isDotViewEnabled = isDotViewEnabled; 607 | } 608 | 609 | public void setConfiguration(MaterialIntroConfiguration configuration) { 610 | 611 | if (configuration != null) { 612 | this.maskColor = configuration.getMaskColor(); 613 | this.delayMillis = configuration.getDelayMillis(); 614 | this.isFadeAnimationEnabled = configuration.isFadeAnimationEnabled(); 615 | this.colorTextViewInfo = configuration.getColorTextViewInfo(); 616 | this.isDotViewEnabled = configuration.isDotViewEnabled(); 617 | this.dismissOnTouch = configuration.isDismissOnTouch(); 618 | this.colorTextViewInfo = configuration.getColorTextViewInfo(); 619 | this.focusType = configuration.getFocusType(); 620 | this.focusGravity = configuration.getFocusGravity(); 621 | } 622 | } 623 | 624 | private void setUsageId(String materialIntroViewId) { 625 | this.materialIntroViewId = materialIntroViewId; 626 | } 627 | 628 | private void setListener(MaterialIntroListener materialIntroListener) { 629 | this.materialIntroListener = materialIntroListener; 630 | } 631 | 632 | private void setPerformClick(boolean isPerformClick){ 633 | this.isPerformClick = isPerformClick; 634 | } 635 | 636 | /** 637 | * Builder Class 638 | */ 639 | public static class Builder { 640 | 641 | private MaterialIntroView materialIntroView; 642 | 643 | private Activity activity; 644 | 645 | private Focus focusType = Focus.MINIMUM; 646 | 647 | public Builder(Activity activity) { 648 | this.activity = activity; 649 | materialIntroView = new MaterialIntroView(activity); 650 | } 651 | 652 | public Builder setMaskColor(int maskColor) { 653 | materialIntroView.setMaskColor(maskColor); 654 | return this; 655 | } 656 | 657 | public Builder setDelayMillis(int delayMillis) { 658 | materialIntroView.setDelay(delayMillis); 659 | return this; 660 | } 661 | 662 | public Builder enableFadeAnimation(boolean isFadeAnimationEnabled) { 663 | materialIntroView.enableFadeAnimation(isFadeAnimationEnabled); 664 | return this; 665 | } 666 | 667 | public Builder setShape(ShapeType shape) { 668 | materialIntroView.setShapeType(shape); 669 | return this; 670 | } 671 | 672 | public Builder setFocusType(Focus focusType) { 673 | materialIntroView.setFocusType(focusType); 674 | return this; 675 | } 676 | 677 | public Builder setFocusGravity(FocusGravity focusGravity) { 678 | materialIntroView.setFocusGravity(focusGravity); 679 | return this; 680 | } 681 | 682 | public Builder setTarget(View view) { 683 | materialIntroView.setTarget(new ViewTarget(view)); 684 | return this; 685 | } 686 | 687 | public Builder setTargetPadding(int padding) { 688 | materialIntroView.setPadding(padding); 689 | return this; 690 | } 691 | 692 | public Builder setTextColor(int textColor) { 693 | materialIntroView.setColorTextViewInfo(textColor); 694 | return this; 695 | } 696 | 697 | public Builder setInfoText(CharSequence infoText) { 698 | materialIntroView.enableInfoDialog(true); 699 | materialIntroView.setTextViewInfo(infoText); 700 | return this; 701 | } 702 | 703 | public Builder setInfoTextSize(int textSize) { 704 | materialIntroView.setTextViewInfoSize(textSize); 705 | return this; 706 | } 707 | 708 | public Builder dismissOnTouch(boolean dismissOnTouch) { 709 | materialIntroView.setDismissOnTouch(dismissOnTouch); 710 | return this; 711 | } 712 | 713 | public Builder setUsageId(String materialIntroViewId) { 714 | materialIntroView.setUsageId(materialIntroViewId); 715 | return this; 716 | } 717 | 718 | public Builder enableDotAnimation(boolean isDotAnimationEnabled) { 719 | materialIntroView.enableDotView(isDotAnimationEnabled); 720 | return this; 721 | } 722 | 723 | public Builder enableIcon(boolean isImageViewIconEnabled) { 724 | materialIntroView.enableImageViewIcon(isImageViewIconEnabled); 725 | return this; 726 | } 727 | 728 | public Builder setIdempotent(boolean idempotent) { 729 | materialIntroView.setIdempotent(idempotent); 730 | return this; 731 | } 732 | 733 | public Builder setConfiguration(MaterialIntroConfiguration configuration) { 734 | materialIntroView.setConfiguration(configuration); 735 | return this; 736 | } 737 | 738 | public Builder setListener(MaterialIntroListener materialIntroListener) { 739 | materialIntroView.setListener(materialIntroListener); 740 | return this; 741 | } 742 | 743 | public Builder setCustomShape(Shape shape) { 744 | materialIntroView.usesCustomShape = true; 745 | materialIntroView.setShape(shape); 746 | return this; 747 | } 748 | 749 | public Builder performClick(boolean isPerformClick){ 750 | materialIntroView.setPerformClick(isPerformClick); 751 | return this; 752 | } 753 | 754 | public MaterialIntroView build() { 755 | if(materialIntroView.usesCustomShape) { 756 | return materialIntroView; 757 | } 758 | 759 | // no custom shape supplied, build our own 760 | Shape shape; 761 | 762 | if(materialIntroView.shapeType == ShapeType.CIRCLE) { 763 | shape = new Circle( 764 | materialIntroView.targetView, 765 | materialIntroView.focusType, 766 | materialIntroView.focusGravity, 767 | materialIntroView.padding); 768 | } else { 769 | shape = new Rect( 770 | materialIntroView.targetView, 771 | materialIntroView.focusType, 772 | materialIntroView.focusGravity, 773 | materialIntroView.padding); 774 | } 775 | 776 | materialIntroView.setShape(shape); 777 | return materialIntroView; 778 | } 779 | 780 | public MaterialIntroView show() { 781 | build().show(activity); 782 | return materialIntroView; 783 | } 784 | 785 | } 786 | 787 | } 788 | -------------------------------------------------------------------------------- /materialintro/src/main/res/drawable/icon_dotview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iammert/MaterialIntroView/f7b36b77d691bd0f2b270b378fab8d1aaf8ea273/materialintro/src/main/res/drawable/icon_dotview.png -------------------------------------------------------------------------------- /materialintro/src/main/res/drawable/icon_question.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iammert/MaterialIntroView/f7b36b77d691bd0f2b270b378fab8d1aaf8ea273/materialintro/src/main/res/drawable/icon_question.png -------------------------------------------------------------------------------- /materialintro/src/main/res/layout/dotview.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /materialintro/src/main/res/layout/material_intro_card.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 20 | 21 | 27 | 28 | 37 | 38 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /materialintro/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 24dp 4 | 16sp 5 | -------------------------------------------------------------------------------- /materialintro/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | materialintro 3 | 4 | -------------------------------------------------------------------------------- /materialintro/src/test/java/co/mobiwise/materialintro/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.materialintro; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample/Demo_Debug.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iammert/MaterialIntroView/f7b36b77d691bd0f2b270b378fab8d1aaf8ea273/sample/Demo_Debug.apk -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 26 5 | buildToolsVersion "26.0.2" 6 | 7 | defaultConfig { 8 | applicationId "co.mobiwise.sample" 9 | minSdkVersion 14 10 | targetSdkVersion 26 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | testCompile 'junit:junit:4.12' 25 | compile 'com.android.support:appcompat-v7:26.1.0' 26 | compile 'com.android.support:design:26.1.0' 27 | //compile 'com.github.iammert:MaterialIntroView:1.5.1' 28 | compile project(':materialintro') 29 | compile 'com.squareup.picasso:picasso:2.5.2' 30 | } 31 | -------------------------------------------------------------------------------- /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/mertsimsek/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /sample/src/androidTest/java/co/mobiwise/sample/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.sample; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /sample/src/main/java/co/mobiwise/sample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.sample; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.design.widget.NavigationView; 6 | import android.support.v4.view.GravityCompat; 7 | import android.support.v4.widget.DrawerLayout; 8 | import android.support.v7.app.ActionBarDrawerToggle; 9 | import android.support.v7.app.AppCompatActivity; 10 | import android.support.v7.widget.Toolbar; 11 | import android.view.Menu; 12 | import android.view.MenuItem; 13 | 14 | import co.mobiwise.sample.fragment.FocusFragment; 15 | import co.mobiwise.sample.fragment.GravityFragment; 16 | import co.mobiwise.sample.fragment.MainFragment; 17 | import co.mobiwise.sample.fragment.RecyclerviewFragment; 18 | 19 | public class MainActivity extends AppCompatActivity 20 | implements NavigationView.OnNavigationItemSelectedListener { 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | setContentView(R.layout.activity_main); 26 | final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 27 | setSupportActionBar(toolbar); 28 | 29 | if (savedInstanceState == null) 30 | getSupportFragmentManager() 31 | .beginTransaction() 32 | .add(R.id.container, new MainFragment()) 33 | .commit(); 34 | 35 | 36 | DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); 37 | ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( 38 | this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); 39 | drawer.setDrawerListener(toggle); 40 | toggle.syncState(); 41 | 42 | NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); 43 | navigationView.setNavigationItemSelectedListener(this); 44 | 45 | } 46 | 47 | @Override 48 | public void onBackPressed() { 49 | DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); 50 | if (drawer.isDrawerOpen(GravityCompat.START)) { 51 | drawer.closeDrawer(GravityCompat.START); 52 | } else { 53 | super.onBackPressed(); 54 | } 55 | } 56 | 57 | @Override 58 | public boolean onCreateOptionsMenu(Menu menu) { 59 | // Inflate the menu; this adds items to the action bar if it is present. 60 | getMenuInflater().inflate(R.menu.main, menu); 61 | return true; 62 | } 63 | 64 | @Override 65 | public boolean onOptionsItemSelected(MenuItem item) { 66 | // Handle action bar item clicks here. The action bar will 67 | // automatically handle clicks on the Home/Up button, so long 68 | // as you specify a parent activity in AndroidManifest.xml. 69 | int id = item.getItemId(); 70 | 71 | //noinspection SimplifiableIfStatement 72 | if (id == R.id.action_settings) { 73 | return true; 74 | } 75 | 76 | return super.onOptionsItemSelected(item); 77 | } 78 | 79 | @Override 80 | public boolean onNavigationItemSelected(MenuItem item) { 81 | // Handle navigation view item clicks here. 82 | switch (item.getItemId()) { 83 | case R.id.nav_demo: 84 | getSupportFragmentManager().beginTransaction().replace(R.id.container, new MainFragment()).commit(); 85 | break; 86 | case R.id.nav_gravity: 87 | getSupportFragmentManager().beginTransaction().replace(R.id.container, new GravityFragment()).commit(); 88 | break; 89 | case R.id.nav_focus: 90 | getSupportFragmentManager().beginTransaction().replace(R.id.container, new FocusFragment()).commit(); 91 | break; 92 | case R.id.nav_recyclerview: 93 | getSupportFragmentManager().beginTransaction().replace(R.id.container, new RecyclerviewFragment()).commit(); 94 | break; 95 | case R.id.nav_toolbar: 96 | startActivity(new Intent(getApplicationContext(), ToolbarMenuItemActivity.class)); 97 | break; 98 | case R.id.nav_tab: 99 | break; 100 | default: 101 | break; 102 | } 103 | DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); 104 | drawer.closeDrawer(GravityCompat.START); 105 | return true; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /sample/src/main/java/co/mobiwise/sample/ToolbarMenuItemActivity.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.sample; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.design.widget.NavigationView; 6 | import android.support.v4.view.GravityCompat; 7 | import android.support.v4.widget.DrawerLayout; 8 | import android.support.v7.app.ActionBarDrawerToggle; 9 | import android.support.v7.app.AppCompatActivity; 10 | import android.support.v7.widget.Toolbar; 11 | import android.view.Menu; 12 | import android.view.MenuItem; 13 | import android.view.View; 14 | import android.widget.ImageView; 15 | import android.widget.Toast; 16 | 17 | import co.mobiwise.materialintro.animation.MaterialIntroListener; 18 | import co.mobiwise.materialintro.shape.Focus; 19 | import co.mobiwise.materialintro.shape.FocusGravity; 20 | import co.mobiwise.materialintro.view.MaterialIntroView; 21 | import co.mobiwise.sample.fragment.FocusFragment; 22 | import co.mobiwise.sample.fragment.GravityFragment; 23 | import co.mobiwise.sample.fragment.MainFragment; 24 | import co.mobiwise.sample.fragment.RecyclerviewFragment; 25 | 26 | /** 27 | * This activity demonstrates how to implement Material introView on ToolBar MenuItems 28 | * 29 | * @author Thomas Kioko 30 | */ 31 | public class ToolbarMenuItemActivity extends AppCompatActivity 32 | implements NavigationView.OnNavigationItemSelectedListener, MaterialIntroListener { 33 | 34 | private static final String MENU_SHARED_ID_TAG = "menuSharedIdTag"; 35 | private static final String MENU_ABOUT_ID_TAG = "menuAboutIdTag"; 36 | private static final String MENU_SEARCH_ID_TAG = "menuSearchIdTag"; 37 | private ImageView mIvShare, mIvAbout; 38 | 39 | @Override 40 | protected void onCreate(Bundle savedInstanceState) { 41 | super.onCreate(savedInstanceState); 42 | setContentView(R.layout.activity_toolbar); 43 | final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 44 | setSupportActionBar(toolbar); 45 | 46 | //User toolbar to access the views 47 | ImageView ivSearch = (ImageView) toolbar.findViewById(R.id.ivToolbarSearch); 48 | mIvShare = (ImageView) toolbar.findViewById(R.id.ivToolbarShare); 49 | mIvAbout = (ImageView) toolbar.findViewById(R.id.ivToolbarAbout); 50 | 51 | DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); 52 | ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( 53 | this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); 54 | drawer.setDrawerListener(toggle); 55 | toggle.syncState(); 56 | 57 | NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); 58 | navigationView.setNavigationItemSelectedListener(this); 59 | 60 | //show the intro view 61 | showIntro(ivSearch, MENU_SEARCH_ID_TAG, getString(R.string.guide_setup_profile), FocusGravity.CENTER); 62 | 63 | } 64 | 65 | @Override 66 | public void onBackPressed() { 67 | DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); 68 | if (drawer.isDrawerOpen(GravityCompat.START)) { 69 | drawer.closeDrawer(GravityCompat.START); 70 | } else { 71 | super.onBackPressed(); 72 | } 73 | } 74 | 75 | @Override 76 | public boolean onCreateOptionsMenu(Menu menu) { 77 | // Inflate the menu; this adds items to the action bar if it is present. 78 | getMenuInflater().inflate(R.menu.main, menu); 79 | return true; 80 | } 81 | 82 | @Override 83 | public boolean onOptionsItemSelected(MenuItem item) { 84 | // Handle action bar item clicks here. The action bar will 85 | // automatically handle clicks on the Home/Up button, so long 86 | // as you specify a parent activity in AndroidManifest.xml. 87 | int id = item.getItemId(); 88 | 89 | //noinspection SimplifiableIfStatement 90 | if (id == R.id.action_settings) { 91 | return true; 92 | } 93 | 94 | return super.onOptionsItemSelected(item); 95 | } 96 | 97 | @Override 98 | public boolean onNavigationItemSelected(MenuItem item) { 99 | // Handle navigation view item clicks here. 100 | switch (item.getItemId()) { 101 | case R.id.nav_demo: 102 | getSupportFragmentManager().beginTransaction().replace(R.id.container, new MainFragment()).commit(); 103 | break; 104 | case R.id.nav_gravity: 105 | getSupportFragmentManager().beginTransaction().replace(R.id.container, new GravityFragment()).commit(); 106 | break; 107 | case R.id.nav_focus: 108 | getSupportFragmentManager().beginTransaction().replace(R.id.container, new FocusFragment()).commit(); 109 | break; 110 | case R.id.nav_recyclerview: 111 | getSupportFragmentManager().beginTransaction().replace(R.id.container, new RecyclerviewFragment()).commit(); 112 | break; 113 | case R.id.nav_toolbar: 114 | startActivity(new Intent(getApplicationContext(), ToolbarMenuItemActivity.class)); 115 | break; 116 | case R.id.nav_tab: 117 | break; 118 | default: 119 | break; 120 | } 121 | 122 | DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); 123 | drawer.closeDrawer(GravityCompat.START); 124 | return true; 125 | } 126 | 127 | /** 128 | * Method that handles display of intro screens 129 | * 130 | * @param view View to show guide 131 | * @param id Unique ID 132 | * @param text Display message 133 | * @param focusGravity Focus Gravity of the display 134 | */ 135 | public void showIntro(View view, String id, String text, FocusGravity focusGravity) { 136 | new MaterialIntroView.Builder(ToolbarMenuItemActivity.this) 137 | .enableDotAnimation(true) 138 | .setFocusGravity(focusGravity) 139 | .setFocusType(Focus.MINIMUM) 140 | .setDelayMillis(100) 141 | .enableFadeAnimation(true) 142 | .performClick(true) 143 | .setInfoText(text) 144 | .setTarget(view) 145 | .setListener(this) 146 | .setUsageId(id) 147 | .show(); 148 | } 149 | 150 | @Override 151 | public void onUserClicked(String materialIntroViewId) { 152 | switch (materialIntroViewId) { 153 | case MENU_SEARCH_ID_TAG: 154 | showIntro(mIvAbout, MENU_ABOUT_ID_TAG, getString(R.string.guide_setup_profile), FocusGravity.LEFT); 155 | break; 156 | case MENU_ABOUT_ID_TAG: 157 | showIntro(mIvShare, MENU_SHARED_ID_TAG, getString(R.string.guide_setup_profile), FocusGravity.LEFT); 158 | break; 159 | case MENU_SHARED_ID_TAG: 160 | Toast.makeText(ToolbarMenuItemActivity.this, "Complete!", Toast.LENGTH_SHORT).show(); 161 | break; 162 | default: 163 | break; 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /sample/src/main/java/co/mobiwise/sample/adapter/RecyclerViewAdapter.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.sample.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | import android.widget.TextView; 10 | 11 | import com.squareup.picasso.Picasso; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | import co.mobiwise.sample.R; 17 | import co.mobiwise.sample.model.Song; 18 | 19 | public class RecyclerViewAdapter extends RecyclerView.Adapter { 20 | 21 | private List songList; 22 | private Context context; 23 | 24 | public RecyclerViewAdapter(Context context) { 25 | songList = new ArrayList<>(); 26 | this.context = context; 27 | } 28 | 29 | @Override 30 | public RecyclerViewAdapter.ExampleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 31 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_card, parent, false); 32 | ExampleViewHolder holder = new ExampleViewHolder(view); 33 | return holder; 34 | } 35 | 36 | @Override 37 | public void onBindViewHolder(RecyclerViewAdapter.ExampleViewHolder holder, int position) { 38 | Song song = songList.get(position); 39 | 40 | holder.coverName.setText(song.songName); 41 | holder.singerName.setText(song.singerName); 42 | Picasso.with(context).load(song.songArt).into(holder.coverIamge); 43 | } 44 | 45 | @Override 46 | public int getItemCount() { 47 | return songList.size(); 48 | } 49 | 50 | public void setSongList(List songList) { 51 | this.songList = songList; 52 | notifyDataSetChanged(); 53 | } 54 | 55 | 56 | public class ExampleViewHolder extends RecyclerView.ViewHolder { 57 | 58 | ImageView coverIamge; 59 | TextView coverName, singerName; 60 | 61 | public ExampleViewHolder(View itemView) { 62 | super(itemView); 63 | coverIamge = (ImageView) itemView.findViewById(R.id.cover_photo); 64 | coverName = (TextView) itemView.findViewById(R.id.cover_name); 65 | singerName = (TextView) itemView.findViewById(R.id.singer_name); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /sample/src/main/java/co/mobiwise/sample/fragment/FocusFragment.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.sample.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.Button; 10 | 11 | import co.mobiwise.materialintro.animation.MaterialIntroListener; 12 | import co.mobiwise.materialintro.shape.Focus; 13 | import co.mobiwise.materialintro.shape.FocusGravity; 14 | import co.mobiwise.materialintro.view.MaterialIntroView; 15 | import co.mobiwise.sample.R; 16 | 17 | /** 18 | * Created by mertsimsek on 31/01/16. 19 | */ 20 | public class FocusFragment extends Fragment implements MaterialIntroListener{ 21 | 22 | private static final String INTRO_FOCUS_1 = "intro_focus_1"; 23 | private static final String INTRO_FOCUS_2 = "intro_focus_2"; 24 | private static final String INTRO_FOCUS_3 = "intro_focus_3"; 25 | 26 | Button button1; 27 | Button button2; 28 | Button button3; 29 | 30 | @Nullable 31 | @Override 32 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 33 | View view = inflater.inflate(R.layout.fragment_focus, container, false); 34 | 35 | button1 = (Button) view.findViewById(R.id.button_focus_1); 36 | button2 = (Button) view.findViewById(R.id.button_focus_2); 37 | button3 = (Button) view.findViewById(R.id.button_focus_3); 38 | 39 | showIntro(button1,INTRO_FOCUS_1,"This intro view focus on all target.", Focus.ALL); 40 | 41 | return view; 42 | } 43 | 44 | public void showIntro(View view, String id, String text, Focus focusType){ 45 | new MaterialIntroView.Builder(getActivity()) 46 | .enableDotAnimation(false) 47 | .setFocusGravity(FocusGravity.CENTER) 48 | .setFocusType(focusType) 49 | .setDelayMillis(200) 50 | .enableFadeAnimation(true) 51 | .setListener(this) 52 | .performClick(true) 53 | .setInfoText(text) 54 | .setTarget(view) 55 | .setUsageId(id) //THIS SHOULD BE UNIQUE ID 56 | .show(); 57 | } 58 | 59 | @Override 60 | public void onUserClicked(String materialIntroViewId) { 61 | if(materialIntroViewId == INTRO_FOCUS_1) 62 | showIntro(button2,INTRO_FOCUS_2,"This intro view focus on minimum size", Focus.MINIMUM); 63 | else if(materialIntroViewId == INTRO_FOCUS_2) 64 | showIntro(button3,INTRO_FOCUS_3,"This intro view focus on normal size (avarage of MIN and ALL)", Focus.NORMAL); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /sample/src/main/java/co/mobiwise/sample/fragment/GravityFragment.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.sample.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v7.widget.CardView; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | 11 | import co.mobiwise.materialintro.animation.MaterialIntroListener; 12 | import co.mobiwise.materialintro.shape.Focus; 13 | import co.mobiwise.materialintro.shape.FocusGravity; 14 | import co.mobiwise.materialintro.view.MaterialIntroView; 15 | import co.mobiwise.sample.R; 16 | 17 | /** 18 | * Created by mertsimsek on 31/01/16. 19 | */ 20 | public class GravityFragment extends Fragment implements MaterialIntroListener{ 21 | 22 | private static final String INTRO_CARD1 = "intro_card_1"; 23 | private static final String INTRO_CARD2 = "intro_card_2"; 24 | private static final String INTRO_CARD3 = "intro_card_3"; 25 | 26 | CardView cardView1; 27 | CardView cardView2; 28 | CardView cardView3; 29 | 30 | @Nullable 31 | @Override 32 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 33 | View view = inflater.inflate(R.layout.fragment_gravity, container, false); 34 | 35 | cardView1 = (CardView) view.findViewById(R.id.my_card); 36 | cardView2 = (CardView) view.findViewById(R.id.my_card2); 37 | cardView3 = (CardView) view.findViewById(R.id.my_card3); 38 | 39 | showIntro(cardView1, INTRO_CARD1, "This intro focuses on RIGHT", FocusGravity.RIGHT); 40 | 41 | return view; 42 | } 43 | 44 | @Override 45 | public void onUserClicked(String materialIntroViewId) { 46 | if(materialIntroViewId == INTRO_CARD1) 47 | showIntro(cardView2, INTRO_CARD2, "This intro focuses on CENTER.", FocusGravity.CENTER); 48 | if(materialIntroViewId == INTRO_CARD2) 49 | showIntro(cardView3, INTRO_CARD3, "This intro focuses on LEFT.", FocusGravity.LEFT); 50 | } 51 | 52 | public void showIntro(View view, String id, String text, FocusGravity focusGravity){ 53 | new MaterialIntroView.Builder(getActivity()) 54 | .enableDotAnimation(true) 55 | .setFocusGravity(focusGravity) 56 | .setFocusType(Focus.MINIMUM) 57 | .setDelayMillis(200) 58 | .enableFadeAnimation(true) 59 | .performClick(true) 60 | .setInfoText(text) 61 | .setTarget(view) 62 | .setListener(this) 63 | .setUsageId(id) //THIS SHOULD BE UNIQUE ID 64 | .show(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /sample/src/main/java/co/mobiwise/sample/fragment/MainFragment.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.sample.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v7.widget.CardView; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.Button; 11 | 12 | import co.mobiwise.materialintro.prefs.PreferencesManager; 13 | import co.mobiwise.materialintro.shape.Focus; 14 | import co.mobiwise.materialintro.shape.FocusGravity; 15 | import co.mobiwise.materialintro.shape.ShapeType; 16 | import co.mobiwise.materialintro.view.MaterialIntroView; 17 | import co.mobiwise.sample.R; 18 | 19 | /** 20 | * Created by mertsimsek on 31/01/16. 21 | */ 22 | public class MainFragment extends Fragment implements View.OnClickListener{ 23 | 24 | private static final String INTRO_CARD = "material_intro"; 25 | 26 | private CardView cardView; 27 | private Button button; 28 | 29 | @Nullable 30 | @Override 31 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 32 | View view = inflater.inflate(R.layout.content_main, container, false); 33 | cardView = (CardView) view.findViewById(R.id.my_card); 34 | button = (Button) view.findViewById(R.id.button_reset_all); 35 | button.setOnClickListener(this); 36 | 37 | //Show intro 38 | showIntro(cardView, INTRO_CARD, "This is card! Hello There. You can set this text!"); 39 | 40 | return view; 41 | } 42 | 43 | @Override 44 | public void onClick(View v) { 45 | int id = v.getId(); 46 | 47 | if(id == R.id.button_reset_all) 48 | new PreferencesManager(getActivity().getApplicationContext()).resetAll(); 49 | } 50 | 51 | private void showIntro(View view, String usageId, String text){ 52 | new MaterialIntroView.Builder(getActivity()) 53 | .enableDotAnimation(true) 54 | //.enableIcon(false) 55 | .setFocusGravity(FocusGravity.CENTER) 56 | .setFocusType(Focus.MINIMUM) 57 | .setDelayMillis(200) 58 | .enableFadeAnimation(true) 59 | .performClick(true) 60 | .setInfoText(text) 61 | .setTarget(view) 62 | .setShape(ShapeType.RECTANGLE) 63 | .setUsageId(usageId) //THIS SHOULD BE UNIQUE ID 64 | .show(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /sample/src/main/java/co/mobiwise/sample/fragment/RecyclerviewFragment.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.sample.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.os.Handler; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.support.v7.widget.GridLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.Toast; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | import co.mobiwise.materialintro.animation.MaterialIntroListener; 18 | import co.mobiwise.materialintro.shape.Focus; 19 | import co.mobiwise.materialintro.shape.FocusGravity; 20 | import co.mobiwise.materialintro.view.MaterialIntroView; 21 | import co.mobiwise.sample.R; 22 | import co.mobiwise.sample.adapter.RecyclerViewAdapter; 23 | import co.mobiwise.sample.model.Song; 24 | 25 | public class RecyclerviewFragment extends Fragment implements MaterialIntroListener { 26 | 27 | private static final String INTRO_CARD = "recyclerView_material_intro"; 28 | private RecyclerView recyclerView; 29 | private RecyclerViewAdapter adapter; 30 | 31 | @Nullable 32 | @Override 33 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 34 | 35 | View view = inflater.inflate(R.layout.fragment_recyclerview, container, false); 36 | recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); 37 | 38 | initializeRecyclerview(); 39 | loadData(); 40 | 41 | new Handler().postDelayed(new Runnable() { 42 | @Override 43 | public void run() { 44 | showMaterialIntro(); 45 | } 46 | }, 2000); 47 | return view; 48 | } 49 | 50 | private void showMaterialIntro() { 51 | new MaterialIntroView.Builder(getActivity()) 52 | .enableDotAnimation(true) 53 | .setFocusGravity(FocusGravity.CENTER) 54 | .setFocusType(Focus.MINIMUM) 55 | .setDelayMillis(200) 56 | .enableFadeAnimation(true) 57 | .setListener(this) 58 | .performClick(true) 59 | .setInfoText("This intro focuses on Recyclerview item") 60 | .setTarget(recyclerView.getChildAt(2)) 61 | .setUsageId(INTRO_CARD) //THIS SHOULD BE UNIQUE ID 62 | .show(); 63 | } 64 | 65 | private void loadData() { 66 | 67 | Song song = new Song("Diamond", R.drawable.diamond, "Rihanna"); 68 | List songList = new ArrayList<>(); 69 | 70 | for (int i = 0; i < 10; i++) { 71 | songList.add(song); 72 | } 73 | adapter.setSongList(songList); 74 | } 75 | 76 | 77 | private void initializeRecyclerview() { 78 | 79 | RecyclerView.LayoutManager layoutManager = new GridLayoutManager(getActivity(), 2); 80 | recyclerView.setLayoutManager(layoutManager); 81 | recyclerView.setHasFixedSize(true); 82 | 83 | adapter = new RecyclerViewAdapter(getActivity().getApplicationContext()); 84 | recyclerView.setAdapter(adapter); 85 | } 86 | 87 | @Override 88 | public void onUserClicked(String materialIntroViewId) { 89 | if (materialIntroViewId.equals(INTRO_CARD)) { 90 | Toast.makeText(getActivity(), "User Clicked", Toast.LENGTH_SHORT).show(); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /sample/src/main/java/co/mobiwise/sample/model/Song.java: -------------------------------------------------------------------------------- 1 | package co.mobiwise.sample.model; 2 | 3 | public class Song { 4 | 5 | public String songName; 6 | public int songArt; 7 | public String singerName; 8 | 9 | public Song(String songName, int songArt, String singerName) { 10 | this.songName = songName; 11 | this.songArt = songArt; 12 | this.singerName = singerName; 13 | } 14 | } -------------------------------------------------------------------------------- /sample/src/main/res/drawable-v21/ic_menu_camera.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable-v21/ic_menu_gallery.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable-v21/ic_menu_manage.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable-v21/ic_menu_send.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable-v21/ic_menu_share.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable-v21/ic_menu_slideshow.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable/diamond.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iammert/MaterialIntroView/f7b36b77d691bd0f2b270b378fab8d1aaf8ea273/sample/src/main/res/drawable/diamond.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable/icon_miv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iammert/MaterialIntroView/f7b36b77d691bd0f2b270b378fab8d1aaf8ea273/sample/src/main/res/drawable/icon_miv.png -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 16 | 17 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 17 | 18 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/app_bar_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/container.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/content_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 | 24 | 25 | 29 | 30 | 37 | 38 | 46 | 47 | 48 | 49 | 50 |