├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── android ├── android.iml ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── local.properties ├── react-native-shape-image-view.iml └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── reactlibrary │ ├── DownloadImageTask.java │ ├── RNHexagonImageViewModule.java │ ├── RNHexagonViewModule.java │ ├── RNShapeImageViewPackage.java │ └── RNShapeView.java ├── index.js ├── init.js ├── ios ├── RNHexagonView-Bridging-Header.h ├── RNHexagonView.swift ├── RNHexagonViewBridge.m ├── RNHexagonViewManager.swift └── RNShapeImageView.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── simply.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ └── simply.xcuserdatad │ └── xcschemes │ ├── RNShapeImageView.xcscheme │ └── xcschememanagement.plist ├── lib ├── hexagonImage │ ├── hexagonImage.android.js │ ├── hexagonImage.ios.js │ └── index.js ├── hexagonView │ ├── hexagonView.android.js │ ├── hexagonView.ios.js │ └── index.js └── index.js ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | 25 | # Logs 26 | logs 27 | *.log 28 | npm-debug.log* 29 | 30 | # Runtime data 31 | pids 32 | *.pid 33 | *.seed 34 | 35 | # Editor temporary files 36 | android/.idea 37 | .idea 38 | 39 | # Directory for instrumented libs generated by jscoverage/JSCover 40 | lib-cov 41 | 42 | # Coverage directory used by tools like istanbul 43 | coverage 44 | 45 | # nyc test coverage 46 | .nyc_output 47 | 48 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 49 | .grunt 50 | 51 | # node-waf configuration 52 | .lock-wscript 53 | 54 | # Compiled binary addons (http://nodejs.org/api/addons.html) 55 | build/Release 56 | 57 | android/build 58 | 59 | # Dependency directories 60 | node_modules 61 | jspm_packages 62 | 63 | # Optional npm cache directory 64 | .npm 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Common 70 | .DS_Store 71 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Editor temporary files 12 | android/.idea 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # node-waf configuration 27 | .lock-wscript 28 | 29 | # Compiled binary addons (http://nodejs.org/api/addons.html) 30 | build/Release 31 | 32 | # Dependency directories 33 | node_modules 34 | jspm_packages 35 | 36 | # Optional npm cache directory 37 | .npm 38 | 39 | # Optional REPL history 40 | .node_repl_history 41 | 42 | # Common 43 | .DS_Store 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Shahen Hovhannisyan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-shape-image-view 2 | 3 | ## Getting started 4 | 5 | `$ npm install react-native-shape-image-view --save` 6 | 7 | ### Mostly automatic installation 8 | 9 | `$ react-native link react-native-shape-image-view` 10 | 11 | ### Manual installation 12 | 13 | 14 | #### iOS 15 | 16 | 1. In XCode, in the project navigator, right click `Libraries` ➜ `Add Files to [your project's name]` 17 | 2. Go to `node_modules` ➜ `react-native-shape-image-view` and add `RNShapeImageView.xcodeproj` 18 | 3. In XCode, in the project navigator, select your project. Add `libRNShapeImageView.a` to your project's `Build Phases` ➜ `Link Binary With Libraries` 19 | 4. Run your project (`Cmd+R`)< 20 | 21 | #### Android 22 | 23 | 1. Open up `android/app/src/main/java/[...]/MainActivity.java` 24 | - Add `import com.reactlibrary.RNShapeImageViewPackage;` to the imports at the top of the file 25 | - Add `new RNShapeImageViewPackage()` to the list returned by the `getPackages()` method 26 | 2. Append the following lines to `android/settings.gradle`: 27 | ``` 28 | include ':react-native-shape-image-view' 29 | project(':react-native-shape-image-view').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-shape-image-view/android') 30 | ``` 31 | 3. Insert the following lines inside the dependencies block in `android/app/build.gradle`: 32 | ``` 33 | compile project(':react-native-shape-image-view') 34 | ``` 35 | 36 | #### Windows 37 | [Read it! :D](https://github.com/ReactWindows/react-native) 38 | 39 | 1. In Visual Studio add the `RNShapeImageView.sln` in `node_modules/react-native-shape-image-view/windows/RNShapeImageView.sln` folder to their solution, reference from their app. 40 | 2. Open up your `MainPage.cs` app 41 | - Add `using Cl.Json.RNShapeImageView;` to the usings at the top of the file 42 | - Add `new RNShapeImageViewPackage()` to the `List` returned by the `Packages` method 43 | 44 | 45 | ## Usage 46 | 47 | ## HexagonImage (Android only) 48 | ```javascript 49 | import React, { PropTypes } from 'react'; 50 | import { HexagonImage } from 'react-native-shape-image-view'; 51 | 52 | export const Example = () => ( 53 | console.log('hexagon image loaded')} 63 | /> 64 | ); 65 | ``` 66 | 67 | ## HexagonView (Android 4.2+, iOS 8.4+) 68 | ```javascript 69 | import React, { PropTypes } from 'react'; 70 | import { HexagonView } from 'react-native-shape-image-view'; 71 | 72 | export const Example = () => ( 73 | 83 | 87 | 88 | ); 89 | ``` 90 | -------------------------------------------------------------------------------- /android/android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | apply plugin: 'com.android.library' 3 | 4 | android { 5 | compileSdkVersion 23 6 | buildToolsVersion "23.0.1" 7 | 8 | defaultConfig { 9 | minSdkVersion 16 10 | targetSdkVersion 22 11 | versionCode 1 12 | versionName "1.0" 13 | ndk { 14 | abiFilters "armeabi-v7a", "x86" 15 | } 16 | } 17 | lintOptions { 18 | warning 'InvalidPackage' 19 | } 20 | } 21 | 22 | dependencies { 23 | compile 'com.facebook.react:react-native:+' 24 | compile 'com.github.siyamed:android-shape-imageview:0.9.+@aar' 25 | } 26 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahen94/react-native-shape-image-view/4a5ed97fd8fe0b27fec1e0ce31aff13fa4f86590/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip 7 | -------------------------------------------------------------------------------- /android/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 | -------------------------------------------------------------------------------- /android/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 | -------------------------------------------------------------------------------- /android/local.properties: -------------------------------------------------------------------------------- 1 | ## This file is automatically generated by Android Studio. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must *NOT* be checked into Version Control Systems, 5 | # as it contains information specific to your local configuration. 6 | # 7 | # Location of the SDK. This is only used by Gradle. 8 | # For customization when using a Version Control System, please read the 9 | # header note. 10 | #Thu Sep 29 14:09:47 AMT 2016 11 | sdk.dir=/Users/simply/Library/Android/sdk 12 | -------------------------------------------------------------------------------- /android/react-native-shape-image-view.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /android/src/main/java/com/reactlibrary/DownloadImageTask.java: -------------------------------------------------------------------------------- 1 | package com.reactlibrary; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapFactory; 5 | import android.os.AsyncTask; 6 | import android.util.Log; 7 | import android.widget.ImageView; 8 | 9 | 10 | import com.facebook.react.bridge.ReactContext; 11 | import com.facebook.react.modules.core.DeviceEventManagerModule; 12 | 13 | import java.io.InputStream; 14 | import java.net.URL; 15 | 16 | public class DownloadImageTask extends AsyncTask { 17 | private ImageView bmImage; 18 | private ReactContext reactContext; 19 | 20 | public DownloadImageTask(ImageView bmImage, ReactContext reactContext) { 21 | this.bmImage = bmImage; 22 | this.reactContext = reactContext; 23 | } 24 | 25 | protected Bitmap doInBackground(String... urls) { 26 | String urldisplay = urls[0]; 27 | Bitmap mIcon11 = null; 28 | try { 29 | InputStream in = new URL(urldisplay).openStream(); 30 | mIcon11 = BitmapFactory.decodeStream(in); 31 | } catch (Exception e) { 32 | Log.e("Error", e.getMessage()); 33 | e.printStackTrace(); 34 | } 35 | return mIcon11; 36 | } 37 | 38 | protected void onPostExecute(Bitmap result) { 39 | bmImage.setImageBitmap(result); 40 | if (reactContext != null) { 41 | reactContext 42 | .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) 43 | .emit("RNShapeImageView:Loaded", null); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /android/src/main/java/com/reactlibrary/RNHexagonImageViewModule.java: -------------------------------------------------------------------------------- 1 | 2 | package com.reactlibrary; 3 | 4 | import android.graphics.Color; 5 | import android.support.annotation.Nullable; 6 | 7 | import com.facebook.react.bridge.ReactContext; 8 | import com.facebook.react.uimanager.SimpleViewManager; 9 | import com.facebook.react.uimanager.ThemedReactContext; 10 | import com.facebook.react.uimanager.annotations.ReactProp; 11 | import com.github.siyamed.shapeimageview.HexagonImageView; 12 | 13 | public class RNHexagonImageViewModule extends SimpleViewManager { 14 | 15 | private ReactContext reactContext; 16 | private final String LOG_KEY = "HEXAGON_IMAGE_VIEW"; 17 | 18 | public RNHexagonImageViewModule(ReactContext context) { 19 | this.reactContext = context; 20 | } 21 | 22 | @Override 23 | public String getName() { 24 | return "RNHexagonImageView"; 25 | } 26 | 27 | @Override 28 | protected HexagonImageView createViewInstance(ThemedReactContext reactContext) { 29 | return new HexagonImageView(reactContext); 30 | } 31 | 32 | @ReactProp(name="src") 33 | public void setSource(final HexagonImageView view, final String src) { 34 | // Log.d(LOG_KEY, src); 35 | new DownloadImageTask(view, reactContext).execute(src); 36 | } 37 | 38 | private int getColorFromString(String color) { 39 | if (color == null) { 40 | return Color.TRANSPARENT; 41 | } 42 | if (color.startsWith("rgb")) { 43 | String[] colors = color.substring(4, color.length() - 1).split(","); 44 | String hex = String.format("#%02x%02x%02x", 45 | Integer.valueOf(colors[0].trim()), 46 | Integer.valueOf(colors[1].trim()), 47 | Integer.valueOf(colors[2].trim()) 48 | ); 49 | return Color.parseColor(hex); 50 | } 51 | 52 | 53 | return Color.parseColor(color); 54 | } 55 | 56 | @ReactProp(name="backgroundColor") 57 | public void setBackgroundColor(HexagonImageView view, @Nullable String color) { 58 | view.setBackgroundColor(getColorFromString(color)); 59 | } 60 | 61 | @ReactProp(name="borderWidth", defaultInt = 0) 62 | public void setBorderWidth(HexagonImageView view, int width) { 63 | view.setBorderWidth(width); 64 | } 65 | 66 | @ReactProp(name="borderColor") 67 | public void setBorderColor(HexagonImageView view, @Nullable String color) { 68 | view.setBorderColor(getColorFromString(color)); 69 | } 70 | 71 | @Override 72 | public void setAccessibilityLabel(HexagonImageView view, String accessibilityLabel) { 73 | super.setAccessibilityLabel(view, accessibilityLabel); 74 | } 75 | 76 | @Override 77 | public void setAccessibilityComponentType(HexagonImageView view, String accessibilityComponentType) { 78 | super.setAccessibilityComponentType(view, accessibilityComponentType); 79 | } 80 | 81 | @Override 82 | public void setTestId(HexagonImageView view, String testId) { 83 | super.setTestId(view, testId); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /android/src/main/java/com/reactlibrary/RNHexagonViewModule.java: -------------------------------------------------------------------------------- 1 | package com.reactlibrary; 2 | 3 | import android.support.annotation.IntegerRes; 4 | import android.support.annotation.Nullable; 5 | import android.util.Log; 6 | 7 | import com.facebook.react.bridge.ReactContext; 8 | import com.facebook.react.uimanager.annotations.ReactProp; 9 | import com.facebook.react.uimanager.ThemedReactContext; 10 | import com.facebook.react.uimanager.ViewGroupManager; 11 | 12 | public class RNHexagonViewModule extends ViewGroupManager { 13 | 14 | private ReactContext reactContext; 15 | 16 | public RNHexagonViewModule(ReactContext context) { 17 | this.reactContext = context; 18 | } 19 | 20 | @Override 21 | public String getName() { 22 | return "RNHexagonView"; 23 | } 24 | 25 | @Override 26 | protected RNShapeView createViewInstance(ThemedReactContext reactContext) { 27 | return new RNShapeView(reactContext); 28 | } 29 | 30 | @ReactProp(name="strokeWidth", defaultInt = 0) 31 | public void setStrokeWidth(RNShapeView view, @Nullable Integer strokeWidth) { 32 | view.setStrokeWidth(strokeWidth); 33 | } 34 | 35 | @ReactProp(name="strokeColor") 36 | public void setStrokeColor(RNShapeView view, @Nullable Integer strokeColor) { 37 | view.setStrokeColor(strokeColor); 38 | } 39 | 40 | @ReactProp(name="cornerRadius", defaultFloat = 0f) 41 | public void setCornerRadius(RNShapeView view, float cornerRadius) { 42 | view.setCornerRadius(cornerRadius); 43 | } 44 | } -------------------------------------------------------------------------------- /android/src/main/java/com/reactlibrary/RNShapeImageViewPackage.java: -------------------------------------------------------------------------------- 1 | 2 | package com.reactlibrary; 3 | 4 | import java.util.ArrayList; 5 | import java.util.Arrays; 6 | import java.util.Collections; 7 | import java.util.List; 8 | 9 | import com.facebook.react.ReactPackage; 10 | import com.facebook.react.bridge.NativeModule; 11 | import com.facebook.react.bridge.ReactApplicationContext; 12 | import com.facebook.react.uimanager.ViewManager; 13 | import com.facebook.react.bridge.JavaScriptModule; 14 | public class RNShapeImageViewPackage implements ReactPackage { 15 | 16 | @Override 17 | public List createNativeModules(ReactApplicationContext reactContext) { 18 | List modules = new ArrayList<>(); 19 | return modules; 20 | } 21 | 22 | @Override 23 | public List> createJSModules() { 24 | return Collections.emptyList(); 25 | } 26 | 27 | @Override 28 | public List createViewManagers(ReactApplicationContext reactContext) { 29 | return Arrays.asList( 30 | new RNHexagonImageViewModule(reactContext), 31 | new RNHexagonViewModule(reactContext) 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /android/src/main/java/com/reactlibrary/RNShapeView.java: -------------------------------------------------------------------------------- 1 | package com.reactlibrary; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.CornerPathEffect; 7 | import android.graphics.Paint; 8 | import android.graphics.Path; 9 | import android.graphics.PorterDuff; 10 | import android.graphics.Region; 11 | import android.util.AttributeSet; 12 | import android.view.ViewGroup; 13 | 14 | public class RNShapeView extends ViewGroup { 15 | private Path hexagonPath; 16 | private Path hexagonBorderPath; 17 | private Paint mBorderPaint; 18 | private Integer strokeWidth = 0; 19 | private Float cornerRadius = 0.0f; 20 | private int strokeColor = Color.WHITE; 21 | 22 | @Override 23 | protected void onLayout(boolean changed, int l, int t, int r, int b) { 24 | 25 | } 26 | 27 | public RNShapeView(Context context) { 28 | super(context); 29 | init(); 30 | } 31 | 32 | public RNShapeView(Context context, AttributeSet attrs) { 33 | super(context, attrs); 34 | init(); 35 | } 36 | 37 | public RNShapeView(Context context, AttributeSet attrs, int defStyleAttr) { 38 | super(context, attrs, defStyleAttr); 39 | init(); 40 | } 41 | 42 | private void init() { 43 | this.setBackgroundColor(Color.TRANSPARENT); 44 | this.hexagonPath = new Path(); 45 | this.hexagonBorderPath = new Path(); 46 | 47 | this.mBorderPaint = new Paint(); 48 | this.mBorderPaint.setColor(this.strokeColor); 49 | this.mBorderPaint.setStrokeJoin(Paint.Join.ROUND); 50 | this.mBorderPaint.setStrokeCap(Paint.Cap.ROUND); 51 | this.mBorderPaint.setStrokeWidth(this.strokeWidth); 52 | this.mBorderPaint.setStyle(Paint.Style.STROKE); 53 | 54 | CornerPathEffect corEffect = new CornerPathEffect(this.cornerRadius); 55 | this.mBorderPaint.setPathEffect(corEffect); 56 | } 57 | 58 | private float getDx(float radius) { 59 | return radius * ((float) Math.cos(Math.PI / 3)); 60 | } 61 | 62 | private float getDy(float radius) { 63 | return radius * ((float) Math.sin(Math.PI / 3)); 64 | } 65 | 66 | /* 67 | 2 3 68 | ------- 69 | / \ 70 | / \ 71 | / \ 4 72 | 1 \ / 73 | \ / 74 | \ / 75 | ------- 76 | 6 5 77 | */ 78 | 79 | private void calculatePath(float radius) { 80 | float halfRadius = radius / 2f; 81 | float triangleHeight = (float) (Math.sqrt(3.0) * halfRadius); 82 | float centerX = getMeasuredWidth() / 2f; 83 | float centerY = getMeasuredHeight() / 2f; 84 | float borderRadius = this.cornerRadius < halfRadius ? this.cornerRadius : halfRadius; 85 | float delta = borderRadius / 12; // approximately selected number 86 | 87 | this.hexagonPath.reset(); 88 | 89 | // 1 90 | this.hexagonPath.moveTo(centerX - radius + getDx(borderRadius), centerY - getDy(borderRadius)); 91 | 92 | // 2 93 | this.hexagonPath.lineTo(centerX - halfRadius - getDx(borderRadius), centerY - triangleHeight + getDy(borderRadius)); 94 | this.hexagonPath.cubicTo( 95 | centerX - halfRadius - getDx(borderRadius), centerY - triangleHeight + getDy(borderRadius), 96 | centerX - halfRadius - delta, centerY - triangleHeight - delta, 97 | centerX - halfRadius + borderRadius, centerY - triangleHeight 98 | ); 99 | 100 | // 3 101 | this.hexagonPath.lineTo(centerX + halfRadius - borderRadius, centerY - triangleHeight); 102 | this.hexagonPath.cubicTo( 103 | centerX + halfRadius - borderRadius, centerY - triangleHeight, 104 | centerX + halfRadius + delta, centerY - triangleHeight - delta, 105 | centerX + halfRadius + getDx(borderRadius), centerY - triangleHeight + getDy(borderRadius) 106 | ); 107 | 108 | // 4 109 | this.hexagonPath.lineTo(centerX + radius - getDx(borderRadius), centerY - getDy(borderRadius)); 110 | this.hexagonPath.cubicTo( 111 | centerX + radius - getDx(borderRadius), centerY - getDy(borderRadius), 112 | centerX + radius + delta, centerY, 113 | centerX + radius - getDx(borderRadius), centerY + getDy(borderRadius) 114 | ); 115 | 116 | // 5 117 | this.hexagonPath.lineTo(centerX + halfRadius + getDx(borderRadius), centerY + triangleHeight - getDy(borderRadius)); 118 | this.hexagonPath.cubicTo( 119 | centerX + halfRadius + getDx(borderRadius), centerY + triangleHeight - getDy(borderRadius), 120 | centerX + halfRadius + delta, centerY + triangleHeight + delta, 121 | centerX + halfRadius - borderRadius, centerY + triangleHeight 122 | ); 123 | 124 | // 6 125 | this.hexagonPath.lineTo(centerX - halfRadius + borderRadius, centerY + triangleHeight); 126 | this.hexagonPath.cubicTo( 127 | centerX - halfRadius + borderRadius, centerY + triangleHeight, 128 | centerX - halfRadius - delta, centerY + triangleHeight + delta, 129 | centerX - halfRadius - getDx(borderRadius), centerY + triangleHeight - getDy(borderRadius) 130 | ); 131 | 132 | // 1 133 | this.hexagonPath.lineTo(centerX - radius + getDx(borderRadius), centerY + getDy(borderRadius)); 134 | this.hexagonPath.cubicTo( 135 | centerX - radius + getDx(borderRadius), centerY + getDy(borderRadius), 136 | centerX - radius - delta, centerY, 137 | centerX - radius + getDx(borderRadius), centerY - getDy(borderRadius) 138 | ); 139 | 140 | this.hexagonPath.close(); 141 | 142 | 143 | float radiusBorder = radius + (float) this.strokeWidth / 2; 144 | float halfRadiusBorder = radiusBorder / 2f; 145 | float triangleBorderHeight = (float) (Math.sqrt(3.0) * halfRadiusBorder); 146 | 147 | this.hexagonBorderPath.reset(); 148 | this.hexagonBorderPath.moveTo(centerX - radiusBorder, centerY); 149 | this.hexagonBorderPath.lineTo(centerX - halfRadiusBorder, centerY - triangleBorderHeight); 150 | this.hexagonBorderPath.lineTo(centerX + halfRadiusBorder, centerY - triangleBorderHeight); 151 | this.hexagonBorderPath.lineTo(centerX + radiusBorder, centerY); 152 | this.hexagonBorderPath.lineTo(centerX + halfRadiusBorder, centerY + triangleBorderHeight); 153 | this.hexagonBorderPath.lineTo(centerX - halfRadiusBorder, centerY + triangleBorderHeight); 154 | this.hexagonBorderPath.close(); 155 | invalidate(); 156 | } 157 | 158 | // private void calculatePath(float radius) { 159 | // float halfRadius = radius / 2f; 160 | // float triangleHeight = (float) (Math.sqrt(3.0) * halfRadius); 161 | // float centerX = getMeasuredWidth() / 2f; 162 | // float centerY = getMeasuredHeight() / 2f; 163 | // 164 | // this.hexagonPath.reset(); 165 | // this.hexagonPath.moveTo(centerX, centerY + radius); 166 | // this.hexagonPath.lineTo(centerX - triangleHeight, centerY + halfRadius); 167 | // this.hexagonPath.lineTo(centerX - triangleHeight, centerY - halfRadius); 168 | // this.hexagonPath.lineTo(centerX, centerY - radius); 169 | // this.hexagonPath.lineTo(centerX + triangleHeight, centerY - halfRadius); 170 | // this.hexagonPath.lineTo(centerX + triangleHeight, centerY + halfRadius); 171 | // this.hexagonPath.close(); 172 | // 173 | // float radiusBorder = radius - 5f; 174 | // float halfRadiusBorder = radiusBorder / 2f; 175 | // float triangleBorderHeight = (float) (Math.sqrt(3.0) * halfRadiusBorder); 176 | // 177 | // this.hexagonBorderPath.reset(); 178 | // this.hexagonBorderPath.moveTo(centerX, centerY + radiusBorder); 179 | // this.hexagonBorderPath.lineTo(centerX - triangleBorderHeight, centerY + halfRadiusBorder); 180 | // this.hexagonBorderPath.lineTo(centerX - triangleBorderHeight, centerY - halfRadiusBorder); 181 | // this.hexagonBorderPath.lineTo(centerX, centerY - radiusBorder); 182 | // this.hexagonBorderPath.lineTo(centerX + triangleBorderHeight, centerY - halfRadiusBorder); 183 | // this.hexagonBorderPath.lineTo(centerX + triangleBorderHeight, centerY + halfRadiusBorder); 184 | // this.hexagonBorderPath.close(); 185 | // invalidate(); 186 | // } 187 | 188 | @Override 189 | public void onDraw(Canvas c) { 190 | c.drawPath(hexagonBorderPath, mBorderPaint); 191 | c.clipPath(hexagonPath, Region.Op.INTERSECT); 192 | c.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); 193 | super.onDraw(c); 194 | } 195 | 196 | @Override 197 | public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){ 198 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 199 | 200 | int width = MeasureSpec.getSize(widthMeasureSpec); 201 | int height = MeasureSpec.getSize(heightMeasureSpec); 202 | 203 | setMeasuredDimension(width, height); 204 | calculatePath(Math.max(width / 2f, height / 2f)); 205 | } 206 | 207 | public void setStrokeWidth(Integer strokeWidth) { 208 | if (this.strokeWidth != strokeWidth) { 209 | this.strokeWidth = strokeWidth; 210 | init(); 211 | } 212 | } 213 | 214 | public void setStrokeColor(Integer strokeColor) { 215 | this.strokeColor = strokeColor; 216 | init(); 217 | } 218 | 219 | public void setCornerRadius(Float cornerRadius) { 220 | if (this.cornerRadius != cornerRadius) { 221 | this.cornerRadius = cornerRadius; 222 | init(); 223 | } 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | export * from './lib'; 2 | -------------------------------------------------------------------------------- /init.js: -------------------------------------------------------------------------------- 1 | const createLibrary = require('react-native-create-library'); 2 | 3 | createLibrary({ 4 | name: 'ShapeImageView' 5 | }).then(() => { 6 | console.log('Oh yay! My library has been created!'); 7 | }) 8 | -------------------------------------------------------------------------------- /ios/RNHexagonView-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #ifndef RNHexagonView_Bridging_Header_h 2 | #define RNHexagonView_Bridging_Header_h 3 | 4 | #import "React/RCTBridgeModule.h" 5 | 6 | #endif /* RNHexagonView_Bridging_Header_h */ 7 | -------------------------------------------------------------------------------- /ios/RNHexagonView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RNHexagonView.swift 3 | // 4 | 5 | import UIKit 6 | 7 | @objc(RNHexagonView) 8 | class RNHexagonView: UIView { 9 | 10 | private var _borderColor: UIColor = .clear 11 | private var _borderWidth: CGFloat = 0 12 | private var _backgroundColor: UIColor = .clear 13 | private var _isHorizontal: Bool = false 14 | private var _size: CGFloat = 0 15 | private var _cornerRadius: CGFloat = 0 16 | 17 | private var borderLayer = CAShapeLayer() 18 | 19 | var size: NSNumber? { 20 | set { 21 | let newSize = RCTConvert.cgFloat(newValue) 22 | self.frame.size.width = newSize 23 | self.frame.size.height = newSize 24 | self.setNeedsDisplay() 25 | } 26 | get { 27 | return nil 28 | } 29 | } 30 | 31 | var borderWidth: NSNumber? { 32 | set { 33 | self._borderWidth = RCTConvert.cgFloat(newValue) 34 | self.setNeedsDisplay() 35 | } 36 | get { 37 | return nil 38 | } 39 | } 40 | 41 | var borderColor: NSString? { 42 | set { 43 | if newValue != nil { 44 | let color = NumberFormatter().number(from: newValue! as String) 45 | self._borderColor = RCTConvert.uiColor(color) 46 | self.setNeedsDisplay() 47 | } 48 | } 49 | get { 50 | return nil 51 | } 52 | } 53 | 54 | var background_Color: NSString? { 55 | set { 56 | if newValue != nil { 57 | let color = NumberFormatter().number(from: newValue! as String) 58 | self._backgroundColor = RCTConvert.uiColor(color) 59 | self.setNeedsDisplay() 60 | } 61 | } 62 | get { 63 | return nil 64 | } 65 | } 66 | 67 | var isHorizontal: NSNumber? { 68 | set { 69 | if let horizontal = newValue { 70 | if self._isHorizontal != RCTConvert.bool(horizontal) { 71 | self._isHorizontal = RCTConvert.bool(horizontal) 72 | self.setNeedsDisplay() 73 | } 74 | } 75 | } 76 | get { 77 | return nil 78 | } 79 | } 80 | 81 | var cornerRadius: NSNumber? { 82 | set { 83 | self._cornerRadius = RCTConvert.cgFloat(newValue) 84 | self.setNeedsDisplay() 85 | } 86 | get { 87 | return nil 88 | } 89 | } 90 | 91 | override func draw(_ rect: CGRect) { 92 | super.draw(rect) 93 | setupHexagonView(view: self) 94 | } 95 | 96 | override func layoutSubviews() { 97 | super.layoutSubviews() 98 | self.backgroundColor = self._backgroundColor 99 | setupHexagonView(view: self) 100 | } 101 | 102 | func setupHexagonView(view: UIView) { 103 | let lineWidth = self._borderWidth 104 | let borderColor = self._borderColor 105 | let rotationOffset = self._isHorizontal ? CGFloat(M_PI) : CGFloat(M_PI / 2.0) 106 | let cornerRadius = self._cornerRadius 107 | 108 | let path = roundedPolygonPath(rect: view.bounds, lineWidth: lineWidth, sides: 6, cornerRadius: cornerRadius, rotationOffset: rotationOffset) 109 | 110 | let mask = CAShapeLayer() 111 | mask.path = path.cgPath 112 | mask.fillColor = UIColor.white.cgColor 113 | (self.layer as! CAShapeLayer).mask = mask 114 | 115 | borderLayer.removeFromSuperlayer() 116 | 117 | (self.layer as! CAShapeLayer).path = path.cgPath 118 | (self.layer as! CAShapeLayer).fillColor = nil 119 | 120 | borderLayer.path = path.cgPath 121 | borderLayer.lineWidth = lineWidth 122 | borderLayer.strokeColor = borderColor.cgColor 123 | borderLayer.fillColor = nil 124 | (self.layer as! CAShapeLayer).addSublayer(borderLayer) 125 | } 126 | 127 | func roundedPolygonPath(rect: CGRect, lineWidth: CGFloat, sides: NSInteger, cornerRadius: CGFloat, rotationOffset: CGFloat = 0) 128 | -> UIBezierPath { 129 | let path = UIBezierPath() 130 | let theta: CGFloat = CGFloat(2.0 * M_PI) / CGFloat(sides) // How much to turn at every corner 131 | // let offset: CGFloat = cornerRadius * tan(theta / 2.0) // Offset from which to start rounding corners 132 | let width = min(rect.size.width, rect.size.height) // Width of the square 133 | 134 | let center = CGPoint(x: rect.origin.x + width / 2.0, y: rect.origin.y + (self._isHorizontal ? 0 : width) / 2.0) 135 | 136 | // Radius of the circle that encircles the polygon 137 | // Notice that the radius is adjusted for the corners, that way the largest outer 138 | // dimension of the resulting shape is always exactly the width - linewidth 139 | let radius = (width - lineWidth + cornerRadius - (cos(theta) * cornerRadius)) / 2.0 140 | 141 | // Start drawing at a point, which by default is at the right hand edge 142 | // but can be offset 143 | var angle = CGFloat(rotationOffset) 144 | 145 | let corner = CGPoint(x: center.x + (radius - cornerRadius) * cos(angle), y: center.y + (radius - cornerRadius) * sin(angle)) 146 | path.move(to: CGPoint(x: corner.x + cornerRadius * cos(angle + theta), y: corner.y + cornerRadius * sin(angle + theta))) 147 | 148 | for _ in 0 ..< sides { 149 | angle += theta 150 | 151 | let corner = CGPoint(x: center.x + (radius - cornerRadius) * cos(angle), y: center.y + (radius - cornerRadius) * sin(angle)) 152 | let tip = CGPoint(x: center.x + radius * cos(angle), y: center.y + radius * sin(angle)) 153 | let start = CGPoint(x: corner.x + cornerRadius * cos(angle - theta), y: corner.y + cornerRadius * sin(angle - theta)) 154 | let end = CGPoint(x: corner.x + cornerRadius * cos(angle + theta), y: corner.y + cornerRadius * sin(angle + theta)) 155 | 156 | path.addLine(to: start) 157 | path.addQuadCurve(to: end, controlPoint: tip) 158 | } 159 | 160 | path.close() 161 | 162 | // Move the path to the correct origins 163 | let bounds = path.bounds 164 | let transform = CGAffineTransform(translationX: -bounds.origin.x + rect.origin.x + lineWidth / 2.0, 165 | y: -bounds.origin.y + rect.origin.y + lineWidth / 2.0) 166 | path.apply(transform) 167 | 168 | return path 169 | } 170 | 171 | override class var layerClass: AnyClass { 172 | return CAShapeLayer.self 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /ios/RNHexagonViewBridge.m: -------------------------------------------------------------------------------- 1 | // 2 | // RNHexagonViewBridge.m 3 | // 4 | 5 | #import 6 | 7 | #import "React/RCTBridgeModule.h" 8 | #import "React/RCTViewManager.h" 9 | 10 | @interface RCT_EXTERN_MODULE(RNHexagonViewManager, RCTViewManager) 11 | 12 | RCT_EXPORT_VIEW_PROPERTY(size, NSNumber) 13 | RCT_EXPORT_VIEW_PROPERTY(borderWidth, NSNumber) 14 | RCT_EXPORT_VIEW_PROPERTY(borderColor, NSString) 15 | RCT_EXPORT_VIEW_PROPERTY(background_Color, NSString) 16 | RCT_EXPORT_VIEW_PROPERTY(isHorizontal, NSNumber) 17 | RCT_EXPORT_VIEW_PROPERTY(cornerRadius, NSNumber) 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /ios/RNHexagonViewManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RNHexagonViewManager.swift 3 | // 4 | 5 | 6 | import UIKit 7 | 8 | @objc(RNHexagonViewManager) 9 | class RNHexagonViewManager: RCTViewManager { 10 | 11 | @objc override func view() -> UIView! { 12 | return RNHexagonView() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ios/RNShapeImageView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 2405F4381DAFCE150098AC5D /* RNShapeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2405F4371DAFCE140098AC5D /* RNShapeView.swift */; }; 11 | 2405F43A1DAFCE230098AC5D /* RNShapeViewBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 2405F4391DAFCE230098AC5D /* RNShapeViewBridge.m */; }; 12 | 2405F43D1DAFCE4C0098AC5D /* RNShapeViewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2405F43C1DAFCE4C0098AC5D /* RNShapeViewManager.swift */; }; 13 | /* End PBXBuildFile section */ 14 | 15 | /* Begin PBXCopyFilesBuildPhase section */ 16 | 58B511D91A9E6C8500147676 /* CopyFiles */ = { 17 | isa = PBXCopyFilesBuildPhase; 18 | buildActionMask = 2147483647; 19 | dstPath = "include/$(PRODUCT_NAME)"; 20 | dstSubfolderSpec = 16; 21 | files = ( 22 | ); 23 | runOnlyForDeploymentPostprocessing = 0; 24 | }; 25 | /* End PBXCopyFilesBuildPhase section */ 26 | 27 | /* Begin PBXFileReference section */ 28 | 134814201AA4EA6300B7C361 /* libRNShapeImageView.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNShapeImageView.a; sourceTree = BUILT_PRODUCTS_DIR; }; 29 | 2405F4371DAFCE140098AC5D /* RNShapeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RNShapeView.swift; sourceTree = ""; }; 30 | 2405F4391DAFCE230098AC5D /* RNShapeViewBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNShapeViewBridge.m; sourceTree = ""; }; 31 | 2405F43B1DAFCE430098AC5D /* RNShapeView-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RNShapeView-Bridging-Header.h"; sourceTree = ""; }; 32 | 2405F43C1DAFCE4C0098AC5D /* RNShapeViewManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RNShapeViewManager.swift; sourceTree = ""; }; 33 | /* End PBXFileReference section */ 34 | 35 | /* Begin PBXFrameworksBuildPhase section */ 36 | 58B511D81A9E6C8500147676 /* Frameworks */ = { 37 | isa = PBXFrameworksBuildPhase; 38 | buildActionMask = 2147483647; 39 | files = ( 40 | ); 41 | runOnlyForDeploymentPostprocessing = 0; 42 | }; 43 | /* End PBXFrameworksBuildPhase section */ 44 | 45 | /* Begin PBXGroup section */ 46 | 134814211AA4EA7D00B7C361 /* Products */ = { 47 | isa = PBXGroup; 48 | children = ( 49 | 134814201AA4EA6300B7C361 /* libRNShapeImageView.a */, 50 | ); 51 | name = Products; 52 | sourceTree = ""; 53 | }; 54 | 2405F4361DAFCDF10098AC5D /* RNShapeView */ = { 55 | isa = PBXGroup; 56 | children = ( 57 | 2405F43C1DAFCE4C0098AC5D /* RNShapeViewManager.swift */, 58 | 2405F43B1DAFCE430098AC5D /* RNShapeView-Bridging-Header.h */, 59 | 2405F4391DAFCE230098AC5D /* RNShapeViewBridge.m */, 60 | 2405F4371DAFCE140098AC5D /* RNShapeView.swift */, 61 | ); 62 | name = RNShapeView; 63 | sourceTree = ""; 64 | }; 65 | 58B511D21A9E6C8500147676 = { 66 | isa = PBXGroup; 67 | children = ( 68 | 2405F4361DAFCDF10098AC5D /* RNShapeView */, 69 | 134814211AA4EA7D00B7C361 /* Products */, 70 | ); 71 | sourceTree = ""; 72 | }; 73 | /* End PBXGroup section */ 74 | 75 | /* Begin PBXNativeTarget section */ 76 | 58B511DA1A9E6C8500147676 /* RNShapeImageView */ = { 77 | isa = PBXNativeTarget; 78 | buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNShapeImageView" */; 79 | buildPhases = ( 80 | 58B511D71A9E6C8500147676 /* Sources */, 81 | 58B511D81A9E6C8500147676 /* Frameworks */, 82 | 58B511D91A9E6C8500147676 /* CopyFiles */, 83 | ); 84 | buildRules = ( 85 | ); 86 | dependencies = ( 87 | ); 88 | name = RNShapeImageView; 89 | productName = RCTDataManager; 90 | productReference = 134814201AA4EA6300B7C361 /* libRNShapeImageView.a */; 91 | productType = "com.apple.product-type.library.static"; 92 | }; 93 | /* End PBXNativeTarget section */ 94 | 95 | /* Begin PBXProject section */ 96 | 58B511D31A9E6C8500147676 /* Project object */ = { 97 | isa = PBXProject; 98 | attributes = { 99 | LastUpgradeCheck = 0800; 100 | ORGANIZATIONNAME = Facebook; 101 | TargetAttributes = { 102 | 58B511DA1A9E6C8500147676 = { 103 | CreatedOnToolsVersion = 6.1.1; 104 | LastSwiftMigration = 0800; 105 | }; 106 | }; 107 | }; 108 | buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNShapeImageView" */; 109 | compatibilityVersion = "Xcode 3.2"; 110 | developmentRegion = English; 111 | hasScannedForEncodings = 0; 112 | knownRegions = ( 113 | en, 114 | ); 115 | mainGroup = 58B511D21A9E6C8500147676; 116 | productRefGroup = 58B511D21A9E6C8500147676; 117 | projectDirPath = ""; 118 | projectRoot = ""; 119 | targets = ( 120 | 58B511DA1A9E6C8500147676 /* RNShapeImageView */, 121 | ); 122 | }; 123 | /* End PBXProject section */ 124 | 125 | /* Begin PBXSourcesBuildPhase section */ 126 | 58B511D71A9E6C8500147676 /* Sources */ = { 127 | isa = PBXSourcesBuildPhase; 128 | buildActionMask = 2147483647; 129 | files = ( 130 | 2405F4381DAFCE150098AC5D /* RNShapeView.swift in Sources */, 131 | 2405F43A1DAFCE230098AC5D /* RNShapeViewBridge.m in Sources */, 132 | 2405F43D1DAFCE4C0098AC5D /* RNShapeViewManager.swift in Sources */, 133 | ); 134 | runOnlyForDeploymentPostprocessing = 0; 135 | }; 136 | /* End PBXSourcesBuildPhase section */ 137 | 138 | /* Begin XCBuildConfiguration section */ 139 | 58B511ED1A9E6C8500147676 /* Debug */ = { 140 | isa = XCBuildConfiguration; 141 | buildSettings = { 142 | ALWAYS_SEARCH_USER_PATHS = NO; 143 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 144 | CLANG_CXX_LIBRARY = "libc++"; 145 | CLANG_ENABLE_MODULES = YES; 146 | CLANG_ENABLE_OBJC_ARC = YES; 147 | CLANG_WARN_BOOL_CONVERSION = YES; 148 | CLANG_WARN_CONSTANT_CONVERSION = YES; 149 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 150 | CLANG_WARN_EMPTY_BODY = YES; 151 | CLANG_WARN_ENUM_CONVERSION = YES; 152 | CLANG_WARN_INFINITE_RECURSION = YES; 153 | CLANG_WARN_INT_CONVERSION = YES; 154 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 155 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 156 | CLANG_WARN_UNREACHABLE_CODE = YES; 157 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 158 | COPY_PHASE_STRIP = NO; 159 | ENABLE_STRICT_OBJC_MSGSEND = YES; 160 | ENABLE_TESTABILITY = YES; 161 | GCC_C_LANGUAGE_STANDARD = gnu99; 162 | GCC_DYNAMIC_NO_PIC = NO; 163 | GCC_NO_COMMON_BLOCKS = YES; 164 | GCC_OPTIMIZATION_LEVEL = 0; 165 | GCC_PREPROCESSOR_DEFINITIONS = ( 166 | "DEBUG=1", 167 | "$(inherited)", 168 | ); 169 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 170 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 171 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 172 | GCC_WARN_UNDECLARED_SELECTOR = YES; 173 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 174 | GCC_WARN_UNUSED_FUNCTION = YES; 175 | GCC_WARN_UNUSED_VARIABLE = YES; 176 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 177 | MTL_ENABLE_DEBUG_INFO = YES; 178 | ONLY_ACTIVE_ARCH = YES; 179 | SDKROOT = iphoneos; 180 | }; 181 | name = Debug; 182 | }; 183 | 58B511EE1A9E6C8500147676 /* Release */ = { 184 | isa = XCBuildConfiguration; 185 | buildSettings = { 186 | ALWAYS_SEARCH_USER_PATHS = NO; 187 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 188 | CLANG_CXX_LIBRARY = "libc++"; 189 | CLANG_ENABLE_MODULES = YES; 190 | CLANG_ENABLE_OBJC_ARC = YES; 191 | CLANG_WARN_BOOL_CONVERSION = YES; 192 | CLANG_WARN_CONSTANT_CONVERSION = YES; 193 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 194 | CLANG_WARN_EMPTY_BODY = YES; 195 | CLANG_WARN_ENUM_CONVERSION = YES; 196 | CLANG_WARN_INFINITE_RECURSION = YES; 197 | CLANG_WARN_INT_CONVERSION = YES; 198 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 199 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 200 | CLANG_WARN_UNREACHABLE_CODE = YES; 201 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 202 | COPY_PHASE_STRIP = YES; 203 | ENABLE_NS_ASSERTIONS = NO; 204 | ENABLE_STRICT_OBJC_MSGSEND = YES; 205 | GCC_C_LANGUAGE_STANDARD = gnu99; 206 | GCC_NO_COMMON_BLOCKS = YES; 207 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 208 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 209 | GCC_WARN_UNDECLARED_SELECTOR = YES; 210 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 211 | GCC_WARN_UNUSED_FUNCTION = YES; 212 | GCC_WARN_UNUSED_VARIABLE = YES; 213 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 214 | MTL_ENABLE_DEBUG_INFO = NO; 215 | SDKROOT = iphoneos; 216 | VALIDATE_PRODUCT = YES; 217 | }; 218 | name = Release; 219 | }; 220 | 58B511F01A9E6C8500147676 /* Debug */ = { 221 | isa = XCBuildConfiguration; 222 | buildSettings = { 223 | CLANG_ENABLE_MODULES = YES; 224 | HEADER_SEARCH_PATHS = ( 225 | "$(inherited)", 226 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 227 | "$(SRCROOT)/../../../React/**", 228 | "$(SRCROOT)/../../react-native/React/**", 229 | ); 230 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 231 | LIBRARY_SEARCH_PATHS = "$(inherited)"; 232 | OTHER_LDFLAGS = "-ObjC"; 233 | PRODUCT_NAME = RNShapeImageView; 234 | SKIP_INSTALL = YES; 235 | SWIFT_OBJC_BRIDGING_HEADER = "RNShapeImageView-Bridging-Header.h"; 236 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 237 | SWIFT_VERSION = 3.0; 238 | }; 239 | name = Debug; 240 | }; 241 | 58B511F11A9E6C8500147676 /* Release */ = { 242 | isa = XCBuildConfiguration; 243 | buildSettings = { 244 | CLANG_ENABLE_MODULES = YES; 245 | HEADER_SEARCH_PATHS = ( 246 | "$(inherited)", 247 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 248 | "$(SRCROOT)/../../../React/**", 249 | "$(SRCROOT)/../../react-native/React/**", 250 | ); 251 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 252 | LIBRARY_SEARCH_PATHS = "$(inherited)"; 253 | OTHER_LDFLAGS = "-ObjC"; 254 | PRODUCT_NAME = RNShapeImageView; 255 | SKIP_INSTALL = YES; 256 | SWIFT_OBJC_BRIDGING_HEADER = "RNShapeImageView-Bridging-Header.h"; 257 | SWIFT_VERSION = 3.0; 258 | }; 259 | name = Release; 260 | }; 261 | /* End XCBuildConfiguration section */ 262 | 263 | /* Begin XCConfigurationList section */ 264 | 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNShapeImageView" */ = { 265 | isa = XCConfigurationList; 266 | buildConfigurations = ( 267 | 58B511ED1A9E6C8500147676 /* Debug */, 268 | 58B511EE1A9E6C8500147676 /* Release */, 269 | ); 270 | defaultConfigurationIsVisible = 0; 271 | defaultConfigurationName = Release; 272 | }; 273 | 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNShapeImageView" */ = { 274 | isa = XCConfigurationList; 275 | buildConfigurations = ( 276 | 58B511F01A9E6C8500147676 /* Debug */, 277 | 58B511F11A9E6C8500147676 /* Release */, 278 | ); 279 | defaultConfigurationIsVisible = 0; 280 | defaultConfigurationName = Release; 281 | }; 282 | /* End XCConfigurationList section */ 283 | }; 284 | rootObject = 58B511D31A9E6C8500147676 /* Project object */; 285 | } 286 | -------------------------------------------------------------------------------- /ios/RNShapeImageView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/RNShapeImageView.xcodeproj/project.xcworkspace/xcuserdata/simply.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shahen94/react-native-shape-image-view/4a5ed97fd8fe0b27fec1e0ce31aff13fa4f86590/ios/RNShapeImageView.xcodeproj/project.xcworkspace/xcuserdata/simply.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /ios/RNShapeImageView.xcodeproj/xcuserdata/simply.xcuserdatad/xcschemes/RNShapeImageView.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /ios/RNShapeImageView.xcodeproj/xcuserdata/simply.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | RNShapeImageView.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 58B511DA1A9E6C8500147676 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /lib/hexagonImage/hexagonImage.android.js: -------------------------------------------------------------------------------- 1 | import { Animated, Dimensions, Image, StyleSheet, View } from 'react-native'; 2 | import React, { Component } from 'react'; 3 | 4 | import { HexagonView } from '../hexagonView'; 5 | import PropTypes from 'prop-types'; 6 | import { isEqual } from 'lodash'; 7 | 8 | const { width: WINDOW_WIDTH, height: WINDOW_HEIGHT } = Dimensions.get('window'); 9 | 10 | const normalSize = WINDOW_WIDTH / 2.5 - WINDOW_HEIGHT / 150; 11 | 12 | const styles = StyleSheet.create({ 13 | fillAbsolute: { 14 | ...StyleSheet.absoluteFillObject, 15 | }, 16 | secondImageView: { 17 | flexGrow: 1, 18 | }, 19 | bumpAtTop: { 20 | marginTop: -13 21 | }, 22 | overlay: { 23 | position: 'absolute', 24 | right: 0, 25 | left: 0, 26 | bottom: 0, 27 | } 28 | }); 29 | 30 | export class HexagonImage extends Component { 31 | static propTypes = { 32 | ...View.propTypes, 33 | ...Image.propTypes, 34 | borderWidth: PropTypes.number, 35 | borderColor: PropTypes.string, 36 | backgroundColor: PropTypes.string, 37 | size: PropTypes.number.isRequired, 38 | isHorizontal: PropTypes.bool, 39 | transitionDuration: PropTypes.number, 40 | src: PropTypes.oneOfType([ 41 | Image.propTypes.source, 42 | PropTypes.arrayOf(Image.propTypes.source) 43 | ]).isRequired, 44 | cornerRadius: PropTypes.number, 45 | animate: PropTypes.bool, 46 | prop: PropTypes.any, 47 | timingBetween: PropTypes.shape({ 48 | min: PropTypes.number, 49 | max: PropTypes.number 50 | }) 51 | }; 52 | 53 | static defaultProps = { 54 | animate: false, 55 | transitionDuration: 500, 56 | timingBetween: { 57 | min: 2000, 58 | max: 5000 59 | } 60 | }; 61 | 62 | constructor(props, context) { 63 | super(props, context); 64 | this.state = { 65 | opacity: new Animated.Value(1), 66 | opacitySecond: new Animated.Value(0), 67 | currImageIndex: 0, 68 | nextImageIndex: 1 69 | }; 70 | this.frameShowedCount = 1; 71 | this.showFrontImage = true; 72 | this.animateViews = this.animateViews.bind(this); 73 | this.reset = this.reset.bind(this); 74 | this.getNextInvocationTimeout = this.getNextInvocationTimeout.bind(this); 75 | this.timeout = null; 76 | this._isMounted = false; 77 | } 78 | 79 | componentWillMount() { 80 | this._isMounted = true; 81 | if ( 82 | !Array.isArray(this.props.src) 83 | || !this.props.animate 84 | || this.props.src.length < 2 85 | ) { 86 | return; 87 | } 88 | this.timeout = setTimeout(() => { 89 | this.animateViews(); 90 | }, this.getNextInvocationTimeout()); 91 | } 92 | 93 | componentWillReceiveProps(nextProps) { 94 | if (!isEqual(this.props.src, nextProps.src)) { 95 | this.reset(); 96 | } 97 | if ( 98 | nextProps.animate !== this.props.animate 99 | || !isEqual(this.props.src, nextProps.src) 100 | ) { 101 | this.clearTimeouts(); 102 | this.timeout = setTimeout(() => { 103 | this.animateViews(nextProps.animate); 104 | }, this.getNextInvocationTimeout()); 105 | } 106 | } 107 | 108 | shouldComponentUpdate(nProps, nState) { 109 | const shouldUpdateProps = !isEqual(this.props, nProps); 110 | const shouldUpdateState = !isEqual(this.state, nState); 111 | 112 | return shouldUpdateState || shouldUpdateProps; 113 | } 114 | 115 | componentWillUnmount() { 116 | this._isMounted = false; 117 | this.clearTimeouts(); 118 | } 119 | 120 | reset() { 121 | this.state.opacity.setValue(1); 122 | this.state.opacitySecond.setValue(0); 123 | 124 | this.frameShowedCount = 1; 125 | this.showFrontImage = true; 126 | 127 | this._isMounted && this.setState({ 128 | currImageIndex: 0, 129 | nextImageIndex: 1 130 | }); 131 | } 132 | 133 | clearTimeouts() { 134 | if (this.timeout) { 135 | clearTimeout(this.timeout); 136 | } 137 | this.timeout = null; 138 | } 139 | 140 | animateViews(useAnimate) { 141 | const { src, animate, transitionDuration } = this.props; 142 | const { currImageIndex, nextImageIndex } = this.state; 143 | const shouldAnimate = typeof useAnimate !== 'undefined' 144 | ? useAnimate 145 | : animate; 146 | 147 | if (!Array.isArray(src) || !shouldAnimate || src.length < 2) { 148 | return; 149 | } 150 | 151 | this.clearTimeouts(); 152 | 153 | const MAX_INDEX = src.length - 1; 154 | const nextInvocation = this.getNextInvocationTimeout(); 155 | const showFrontImage = this.showFrontImage = !this.showFrontImage; 156 | 157 | let nextIndex = this.frameShowedCount === 1 158 | ? currImageIndex + 2 159 | : currImageIndex; 160 | 161 | let prepareIndex = this.frameShowedCount === 2 162 | ? nextImageIndex + 2 163 | : nextImageIndex; 164 | 165 | if (nextIndex > MAX_INDEX) { 166 | nextIndex -= MAX_INDEX; 167 | nextIndex--; 168 | } 169 | if (showFrontImage && prepareIndex > MAX_INDEX) { 170 | prepareIndex -= MAX_INDEX; 171 | prepareIndex--; 172 | } 173 | 174 | Animated.parallel([ 175 | Animated.timing(this.state.opacity, { 176 | toValue: showFrontImage ? 1 : 0, 177 | duration: transitionDuration 178 | }), 179 | Animated.timing(this.state.opacitySecond, { 180 | toValue: showFrontImage ? 0 : 1, 181 | duration: transitionDuration 182 | }), 183 | ]).start(() => { 184 | const nextState = { 185 | currImageIndex: nextIndex, 186 | nextImageIndex: prepareIndex 187 | }; 188 | if (this.frameShowedCount === 2) { 189 | this.frameShowedCount = 1; 190 | } else { 191 | this.frameShowedCount++; 192 | } 193 | 194 | this._isMounted && this.setState(nextState); 195 | }); 196 | this.timeout = setTimeout(() => this.animateViews(), nextInvocation); 197 | } 198 | 199 | getNextInvocationTimeout() { 200 | const { timingBetween } = this.props; 201 | const { min, max } = timingBetween; 202 | return Math.floor(Math.random() * (max - min + 1)) + min; 203 | } 204 | 205 | render() { 206 | const { 207 | children, 208 | borderWidth, 209 | borderColor, 210 | backgroundColor, 211 | size, 212 | isHorizontal, 213 | src, 214 | cornerRadius, 215 | ...props 216 | } = this.props; 217 | const { 218 | currImageIndex, 219 | nextImageIndex, 220 | opacity, 221 | opacitySecond 222 | } = this.state; 223 | const sources = Array.isArray(src) 224 | ? src 225 | : [src]; 226 | 227 | const delta = Math.sqrt(3) * size / 24; 228 | const imageStyle = isHorizontal 229 | ? { bottom: delta } 230 | : { right: delta }; 231 | 232 | return ( 233 | 242 | 251 | {src.length > 1 && ( 252 | 264 | )} 265 | 272 | {children} 273 | 274 | 275 | ); 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /lib/hexagonImage/hexagonImage.ios.js: -------------------------------------------------------------------------------- 1 | import { Animated, Dimensions, Image, StyleSheet, View } from 'react-native'; 2 | import React, { Component } from 'react'; 3 | 4 | import { HexagonView } from '../hexagonView'; 5 | import PropTypes from 'prop-types'; 6 | import { isEqual } from 'lodash'; 7 | 8 | const { width: WINDOW_WIDTH, height: WINDOW_HEIGHT } = Dimensions.get('window'); 9 | 10 | const normalSize = WINDOW_WIDTH / 2.5 - WINDOW_HEIGHT / 150; 11 | 12 | 13 | 14 | const styles = StyleSheet.create({ 15 | fillAbsolute: { 16 | ...StyleSheet.absoluteFillObject, 17 | }, 18 | secondImageView: { 19 | flexGrow: 1, 20 | }, 21 | bumpAtTop: { 22 | marginTop: -13 23 | }, 24 | overlay: { 25 | position: 'absolute', 26 | right: 0, 27 | left: 0, 28 | bottom: 0, 29 | } 30 | }); 31 | 32 | export class HexagonImage extends Component { 33 | static propTypes = { 34 | ...View.propTypes, 35 | ...Image.propTypes, 36 | borderWidth: PropTypes.number, 37 | borderColor: PropTypes.string, 38 | backgroundColor: PropTypes.string, 39 | background_Color: PropTypes.string, 40 | size: PropTypes.number.isRequired, 41 | isHorizontal: PropTypes.bool, 42 | transitionDuration: PropTypes.number, 43 | src: PropTypes.oneOfType([ 44 | Image.propTypes.source, 45 | PropTypes.arrayOf(Image.propTypes.source) 46 | ]).isRequired, 47 | cornerRadius: PropTypes.number, 48 | animate: PropTypes.bool, 49 | prop: PropTypes.any, 50 | timingBetween: PropTypes.shape({ 51 | min: PropTypes.number, 52 | max: PropTypes.number 53 | }) 54 | }; 55 | static defaultProps = { 56 | animate: false, 57 | transitionDuration: 500, 58 | timingBetween: { 59 | min: 2000, 60 | max: 5000 61 | } 62 | }; 63 | constructor(props, context) { 64 | super(props, context); 65 | this.state = { 66 | opacity: new Animated.Value(1), 67 | opacitySecond: new Animated.Value(0), 68 | currImageIndex: 0, 69 | nextImageIndex: 1 70 | }; 71 | this.frameShowedCount = 1; 72 | this.showFrontImage = true; 73 | this.animateViews = this.animateViews.bind(this); 74 | this.reset = this.reset.bind(this); 75 | this.getNextInvocationTimeout = this.getNextInvocationTimeout.bind(this); 76 | this.timeout = null; 77 | this._isMounted = false; 78 | } 79 | componentWillMount() { 80 | this._isMounted = true; 81 | if ( 82 | !Array.isArray(this.props.src) 83 | || !this.props.animate 84 | || this.props.src.length < 2 85 | ) { 86 | return; 87 | } 88 | this.timeout = setTimeout(() => { 89 | this.animateViews(); 90 | }, this.getNextInvocationTimeout()); 91 | } 92 | 93 | componentWillReceiveProps(nextProps) { 94 | if (!isEqual(this.props.src, nextProps.src)) { 95 | this.reset(); 96 | } 97 | if ( 98 | nextProps.animate !== this.props.animate 99 | || !isEqual(this.props.src, nextProps.src) 100 | ) { 101 | this.clearTimeouts(); 102 | this.timeout = setTimeout(() => { 103 | this.animateViews(nextProps.animate); 104 | }, this.getNextInvocationTimeout()); 105 | } 106 | } 107 | 108 | shouldComponentUpdate(nProps, nState) { 109 | const shouldUpdateProps = !isEqual(this.props, nProps); 110 | const shouldUpdateState = !isEqual(this.state, nState); 111 | 112 | return shouldUpdateState || shouldUpdateProps; 113 | } 114 | 115 | componentWillUnmount() { 116 | this._isMounted = false; 117 | this.clearTimeouts(); 118 | } 119 | 120 | reset() { 121 | this.state.opacity.setValue(1); 122 | this.state.opacitySecond.setValue(0); 123 | 124 | this.frameShowedCount = 1; 125 | this.showFrontImage = true; 126 | 127 | this._isMounted && this.setState({ 128 | currImageIndex: 0, 129 | nextImageIndex: 1 130 | }); 131 | } 132 | 133 | clearTimeouts() { 134 | if (this.timeout) { 135 | clearTimeout(this.timeout); 136 | } 137 | this.timeout = null; 138 | } 139 | 140 | animateViews(useAnimate) { 141 | const { src, animate, transitionDuration } = this.props; 142 | const { currImageIndex, nextImageIndex } = this.state; 143 | const shouldAnimate = typeof useAnimate !== 'undefined' 144 | ? useAnimate 145 | : animate; 146 | 147 | if (!Array.isArray(src) || !shouldAnimate || src.length < 2) { 148 | return; 149 | } 150 | 151 | this.clearTimeouts(); 152 | 153 | const MAX_INDEX = src.length - 1; 154 | const nextInvocation = this.getNextInvocationTimeout(); 155 | const showFrontImage = this.showFrontImage = !this.showFrontImage; 156 | 157 | let nextIndex = this.frameShowedCount === 1 158 | ? currImageIndex + 2 159 | : currImageIndex; 160 | 161 | let prepareIndex = this.frameShowedCount === 2 162 | ? nextImageIndex + 2 163 | : nextImageIndex; 164 | 165 | if (nextIndex > MAX_INDEX) { 166 | nextIndex -= MAX_INDEX; 167 | nextIndex--; 168 | } 169 | if (showFrontImage && prepareIndex > MAX_INDEX) { 170 | prepareIndex -= MAX_INDEX; 171 | prepareIndex--; 172 | } 173 | 174 | // console.debug( 175 | // `max index: ${src.length - 1} \n`, 176 | // `nextIndex: ${nextIndex} \n`, 177 | // `prepareIndex: ${prepareIndex} \n`, 178 | // `showFrontImage: ${showFrontImage} \n`, 179 | // `showed image index: ${showFrontImage ? nextIndex : prepareIndex}` 180 | // ); 181 | 182 | 183 | Animated.parallel([ 184 | Animated.timing(this.state.opacity, { 185 | toValue: showFrontImage ? 1 : 0, 186 | duration: transitionDuration 187 | }), 188 | Animated.timing(this.state.opacitySecond, { 189 | toValue: showFrontImage ? 0 : 1, 190 | duration: transitionDuration 191 | }), 192 | ]).start(() => { 193 | const nextState = { 194 | currImageIndex: nextIndex, 195 | nextImageIndex: prepareIndex 196 | }; 197 | if (this.frameShowedCount === 2) { 198 | this.frameShowedCount = 1; 199 | } else { 200 | this.frameShowedCount++; 201 | } 202 | 203 | this._isMounted && this.setState(nextState); 204 | }); 205 | this.timeout = setTimeout(() => this.animateViews(), nextInvocation); 206 | } 207 | 208 | getNextInvocationTimeout() { 209 | const { timingBetween } = this.props; 210 | const { min, max } = timingBetween; 211 | return Math.floor(Math.random() * (max - min + 1)) + min; 212 | } 213 | 214 | render() { 215 | const { 216 | children, 217 | borderWidth, 218 | borderColor, 219 | backgroundColor, 220 | size, 221 | isHorizontal, 222 | src, 223 | cornerRadius, 224 | ...props 225 | } = this.props; 226 | const { 227 | currImageIndex, 228 | nextImageIndex, 229 | opacity, 230 | opacitySecond 231 | } = this.state; 232 | const sources = Array.isArray(src) 233 | ? src 234 | : [src]; 235 | 236 | const delta = Math.sqrt(3) * size / 24; 237 | const imageStyle = isHorizontal 238 | ? { bottom: delta } 239 | : { right: delta }; 240 | 241 | return ( 242 | 250 | 259 | {src.length > 1 && ( 260 | 272 | )} 273 | 280 | {children} 281 | 282 | 283 | ); 284 | } 285 | } 286 | -------------------------------------------------------------------------------- /lib/hexagonImage/index.js: -------------------------------------------------------------------------------- 1 | export { HexagonImage } from './hexagonImage'; 2 | -------------------------------------------------------------------------------- /lib/hexagonView/hexagonView.android.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { View, processColor, requireNativeComponent } from 'react-native'; 3 | 4 | import PropTypes from 'prop-types'; 5 | 6 | export const HexagonView = ({ 7 | children, 8 | borderWidth, 9 | borderColor, 10 | ...props 11 | }) => ( 12 | 17 | {children} 18 | 19 | ); 20 | 21 | HexagonView.propTypes = { 22 | ...View.propTypes, 23 | props: PropTypes.any, 24 | borderWidth: PropTypes.number, 25 | borderColor: PropTypes.string, 26 | strokeWidth: PropTypes.number, 27 | strokeColor: PropTypes.number, 28 | isHorizontal: PropTypes.bool, 29 | cornerRadius: PropTypes.number, 30 | }; 31 | 32 | HexagonView.defaultProps = { 33 | borderWidth: 0, 34 | cornerRadius: 0, 35 | }; 36 | 37 | const RNHexagonView = requireNativeComponent('RNHexagonView', HexagonView); 38 | -------------------------------------------------------------------------------- /lib/hexagonView/hexagonView.ios.js: -------------------------------------------------------------------------------- 1 | import { View, processColor, requireNativeComponent } from 'react-native'; 2 | 3 | import PropTypes from 'prop-types'; 4 | import React from 'react'; 5 | 6 | export const HexagonView = ({ 7 | children, 8 | borderWidth, 9 | borderColor, 10 | backgroundColor, 11 | size, 12 | cornerRadius, 13 | isHorizontal, 14 | ...props 15 | }) => ( 16 | 25 | {children} 26 | 27 | ); 28 | 29 | HexagonView.propTypes = { 30 | ...View.propTypes, 31 | borderWidth: PropTypes.number, 32 | borderColor: PropTypes.string, 33 | backgroundColor: PropTypes.string, 34 | background_Color: PropTypes.string, 35 | size: PropTypes.number.isRequired, 36 | cornerRadius: PropTypes.number, 37 | isHorizontal: PropTypes.bool, 38 | prop: PropTypes.any 39 | }; 40 | HexagonView.defaultProps = { 41 | isHorizontal: false, 42 | borderWidth: 0, 43 | borderColor: 'transparent', 44 | backgroundColor: 'white', 45 | }; 46 | 47 | const RNHexagonView = requireNativeComponent('RNHexagonView', HexagonView); 48 | -------------------------------------------------------------------------------- /lib/hexagonView/index.js: -------------------------------------------------------------------------------- 1 | export { HexagonView } from './hexagonView'; 2 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | export { HexagonImage } from './hexagonImage'; 2 | export { HexagonView } from './hexagonView'; 3 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-shape-image-view", 3 | "version": "2.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "asap": { 8 | "version": "2.0.6", 9 | "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", 10 | "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" 11 | }, 12 | "core-js": { 13 | "version": "1.2.7", 14 | "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", 15 | "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" 16 | }, 17 | "encoding": { 18 | "version": "0.1.12", 19 | "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", 20 | "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", 21 | "requires": { 22 | "iconv-lite": "~0.4.13" 23 | } 24 | }, 25 | "fbjs": { 26 | "version": "0.8.16", 27 | "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz", 28 | "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=", 29 | "requires": { 30 | "core-js": "^1.0.0", 31 | "isomorphic-fetch": "^2.1.1", 32 | "loose-envify": "^1.0.0", 33 | "object-assign": "^4.1.0", 34 | "promise": "^7.1.1", 35 | "setimmediate": "^1.0.5", 36 | "ua-parser-js": "^0.7.9" 37 | } 38 | }, 39 | "iconv-lite": { 40 | "version": "0.4.23", 41 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", 42 | "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", 43 | "requires": { 44 | "safer-buffer": ">= 2.1.2 < 3" 45 | } 46 | }, 47 | "is-stream": { 48 | "version": "1.1.0", 49 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", 50 | "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" 51 | }, 52 | "isomorphic-fetch": { 53 | "version": "2.2.1", 54 | "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", 55 | "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", 56 | "requires": { 57 | "node-fetch": "^1.0.1", 58 | "whatwg-fetch": ">=0.10.0" 59 | } 60 | }, 61 | "js-tokens": { 62 | "version": "3.0.2", 63 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", 64 | "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" 65 | }, 66 | "lodash": { 67 | "version": "4.17.10", 68 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", 69 | "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" 70 | }, 71 | "loose-envify": { 72 | "version": "1.3.1", 73 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", 74 | "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", 75 | "requires": { 76 | "js-tokens": "^3.0.0" 77 | } 78 | }, 79 | "node-fetch": { 80 | "version": "1.7.3", 81 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", 82 | "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", 83 | "requires": { 84 | "encoding": "^0.1.11", 85 | "is-stream": "^1.0.1" 86 | } 87 | }, 88 | "object-assign": { 89 | "version": "4.1.1", 90 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 91 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" 92 | }, 93 | "promise": { 94 | "version": "7.3.1", 95 | "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", 96 | "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", 97 | "requires": { 98 | "asap": "~2.0.3" 99 | } 100 | }, 101 | "prop-types": { 102 | "version": "15.6.1", 103 | "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.1.tgz", 104 | "integrity": "sha512-4ec7bY1Y66LymSUOH/zARVYObB23AT2h8cf6e/O6ZALB/N0sqZFEx7rq6EYPX2MkOdKORuooI/H5k9TlR4q7kQ==", 105 | "requires": { 106 | "fbjs": "^0.8.16", 107 | "loose-envify": "^1.3.1", 108 | "object-assign": "^4.1.1" 109 | } 110 | }, 111 | "safer-buffer": { 112 | "version": "2.1.2", 113 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 114 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 115 | }, 116 | "setimmediate": { 117 | "version": "1.0.5", 118 | "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", 119 | "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" 120 | }, 121 | "ua-parser-js": { 122 | "version": "0.7.18", 123 | "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.18.tgz", 124 | "integrity": "sha512-LtzwHlVHwFGTptfNSgezHp7WUlwiqb0gA9AALRbKaERfxwJoiX0A73QbTToxteIAuIaFshhgIZfqK8s7clqgnA==" 125 | }, 126 | "whatwg-fetch": { 127 | "version": "2.0.4", 128 | "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", 129 | "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==" 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-shape-image-view", 3 | "version": "2.0.0", 4 | "description": "Native Custom Shape Images and Views for React-Native", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "react-native", 11 | "react", 12 | "shapes", 13 | "android", 14 | "ios", 15 | "mobile" 16 | ], 17 | "license": "MIT", 18 | "repository": { 19 | "type": "git", 20 | "url": "git@github.com:shahen94/react-native-shape-image-view.git" 21 | }, 22 | "author": "Shahen Hovhannisyan ", 23 | "dependencies": { 24 | "lodash": "latest", 25 | "prop-types": "^15.6.1" 26 | }, 27 | "peerDependencies": { 28 | "react-native": ">=0.29" 29 | } 30 | } 31 | --------------------------------------------------------------------------------