├── circularImageLibrary ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── styles.xml │ │ │ │ └── dimens.xml │ │ │ ├── values-w820dp │ │ │ │ └── dimens.xml │ │ │ └── layout │ │ │ │ └── activity_main.xml │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── com │ │ │ └── flipkart │ │ │ └── circularImageView │ │ │ ├── BitmapDrawer.java │ │ │ ├── IconDrawer.java │ │ │ ├── TextDrawer.java │ │ │ ├── notification │ │ │ ├── RectangularNotificationDrawer.java │ │ │ ├── CircularNotificationDrawer.java │ │ │ └── NotificationDrawer.java │ │ │ ├── OverlayArcDrawer.java │ │ │ ├── IconMatrixGenerator.java │ │ │ ├── MatrixGenerator.java │ │ │ ├── CircularDrawable.java │ │ │ └── DrawerHelper.java │ └── androidTest │ │ └── java │ │ └── com │ │ └── flipkart │ │ └── circularImageView │ │ └── ApplicationTest.java ├── proguard-rules.pro ├── gradle.properties └── build.gradle ├── settings.gradle ├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── drawable │ │ │ │ ├── flipkart.png │ │ │ │ ├── color_strip.png │ │ │ │ ├── katrina_kaif.jpg │ │ │ │ ├── sample_icon.png │ │ │ │ ├── seller_icon.png │ │ │ │ ├── shop_front.png │ │ │ │ ├── flipkart_round.png │ │ │ │ ├── jennifer_aniston.jpg │ │ │ │ ├── chat_bubble_shadow.png │ │ │ │ ├── profile_placeholder.png │ │ │ │ └── sample_icon_square.png │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── styles.xml │ │ │ │ └── dimens.xml │ │ │ ├── values-w820dp │ │ │ │ └── dimens.xml │ │ │ ├── menu │ │ │ │ └── menu_main.xml │ │ │ └── layout │ │ │ │ └── activity_main.xml │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── com │ │ │ └── flipkart │ │ │ └── sample │ │ │ └── circularImage │ │ │ └── MainActivity.java │ └── androidTest │ │ └── java │ │ └── com │ │ └── flipkart │ │ └── sample │ │ └── circularImage │ │ └── ApplicationTest.java ├── proguard-rules.pro └── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── Screenshots ├── Screenshot_overdraw.png └── Screenshot_2015-05-14-18-24-34.png ├── .gitignore ├── gradle.properties ├── README.md ├── gradlew.bat └── gradlew /circularImageLibrary/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':circularImageLibrary' 2 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flipkart-incubator/circular-image/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /Screenshots/Screenshot_overdraw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flipkart-incubator/circular-image/HEAD/Screenshots/Screenshot_overdraw.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/flipkart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flipkart-incubator/circular-image/HEAD/app/src/main/res/drawable/flipkart.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/color_strip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flipkart-incubator/circular-image/HEAD/app/src/main/res/drawable/color_strip.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/katrina_kaif.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flipkart-incubator/circular-image/HEAD/app/src/main/res/drawable/katrina_kaif.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/sample_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flipkart-incubator/circular-image/HEAD/app/src/main/res/drawable/sample_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/seller_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flipkart-incubator/circular-image/HEAD/app/src/main/res/drawable/seller_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/shop_front.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flipkart-incubator/circular-image/HEAD/app/src/main/res/drawable/shop_front.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/flipkart_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flipkart-incubator/circular-image/HEAD/app/src/main/res/drawable/flipkart_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flipkart-incubator/circular-image/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flipkart-incubator/circular-image/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /Screenshots/Screenshot_2015-05-14-18-24-34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flipkart-incubator/circular-image/HEAD/Screenshots/Screenshot_2015-05-14-18-24-34.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/jennifer_aniston.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flipkart-incubator/circular-image/HEAD/app/src/main/res/drawable/jennifer_aniston.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flipkart-incubator/circular-image/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flipkart-incubator/circular-image/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/chat_bubble_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flipkart-incubator/circular-image/HEAD/app/src/main/res/drawable/chat_bubble_shadow.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/profile_placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flipkart-incubator/circular-image/HEAD/app/src/main/res/drawable/profile_placeholder.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/sample_icon_square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flipkart-incubator/circular-image/HEAD/app/src/main/res/drawable/sample_icon_square.png -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | CircularImageView 3 | 4 | Hello world! 5 | Settings 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /circularImageLibrary/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | CircularImageView 3 | 4 | Hello world! 5 | Settings 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /circularImageLibrary/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /circularImageLibrary/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 10 12:30:35 IST 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip 7 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /circularImageLibrary/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /circularImageLibrary/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # built application files 2 | *.apk 3 | *.ap_ 4 | 5 | #proguard 6 | proguard/ 7 | 8 | # files for the dex VM 9 | *.dex 10 | 11 | # Java class files 12 | *.class 13 | 14 | # generated files 15 | bin/ 16 | gen/ 17 | build/ 18 | 19 | # Local configuration file (sdk path, etc) 20 | local.properties 21 | 22 | #misc 23 | .DS_Store 24 | lint.xml 25 | 26 | # IDEA 27 | *.iml 28 | .idea/ 29 | 30 | # Gradle 31 | .gradle/ 32 | 33 | *.orig 34 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/flipkart/sample/circularImage/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.flipkart.sample.circularImage; 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 | } -------------------------------------------------------------------------------- /circularImageLibrary/src/androidTest/java/com/flipkart/circularImageView/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.flipkart.circularImageView; 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 | } -------------------------------------------------------------------------------- /circularImageLibrary/src/main/java/com/flipkart/circularImageView/BitmapDrawer.java: -------------------------------------------------------------------------------- 1 | package com.flipkart.circularImageView; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapShader; 5 | import android.graphics.Shader; 6 | import android.widget.ImageView; 7 | 8 | /** 9 | * Class that holds all the information to draw a bitmap. 10 | *

11 | * Created by vivek.soneja on 18/02/15. 12 | */ 13 | public class BitmapDrawer { 14 | public Bitmap bitmap; 15 | public Shader bitmapShader; 16 | public ImageView.ScaleType scaleType = ImageView.ScaleType.CENTER_CROP; 17 | } 18 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/vivek.soneja/Development/android-sdks/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 | -------------------------------------------------------------------------------- /circularImageLibrary/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/vivek.soneja/Development/android-sdks/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion "22.0.1" 6 | 7 | defaultConfig { 8 | applicationId "com.flipkart.sample.circularImage" 9 | minSdkVersion 14 10 | targetSdkVersion 21 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | repositories { 23 | maven { url 'http://artifactory.nm.flipkart.com:8081/artifactory/libs-release-local' } 24 | } 25 | 26 | dependencies { 27 | compile fileTree(dir: 'libs', include: ['*.jar']) 28 | compile 'com.android.support:appcompat-v7:21.0.3' 29 | // compile project (':library') 30 | //Custom Artifact for CircularImage 31 | compile project(':circularImageLibrary') 32 | } 33 | -------------------------------------------------------------------------------- /circularImageLibrary/src/main/java/com/flipkart/circularImageView/IconDrawer.java: -------------------------------------------------------------------------------- 1 | package com.flipkart.circularImageView; 2 | 3 | import android.graphics.Bitmap; 4 | 5 | /** 6 | * Holds the information to draw a text. 7 | *

8 | * Created by vivek.soneja on 22/02/15. 9 | */ 10 | public class IconDrawer { 11 | private Bitmap icon; 12 | private float margin; 13 | private int backgroundColor; 14 | 15 | //Setters 16 | public IconDrawer (Bitmap icon, int backgroundColor) { 17 | this.icon = icon; 18 | this.backgroundColor = backgroundColor; 19 | } 20 | 21 | //Getters 22 | public int getBackgroundColor() { 23 | return backgroundColor; 24 | } 25 | 26 | public Bitmap getIcon() { 27 | return icon; 28 | } 29 | 30 | public float getMargin() { 31 | return margin; 32 | } 33 | 34 | /** 35 | * @param margin Margin to be left outside the icon 36 | * @return IconDrawer for chaining 37 | */ 38 | public IconDrawer setMargin(float margin) { 39 | this.margin = margin; 40 | return this; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | ## Project-wide Gradle settings. 2 | # 3 | # For more details on how to configure your build environment visit 4 | # http://www.gradle.org/docs/current/userguide/build_environment.html 5 | # 6 | # Specifies the JVM arguments used for the daemon process. 7 | # The setting is particularly useful for tweaking memory settings. 8 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 10 | # 11 | # When configured, Gradle will run in incubating parallel mode. 12 | # This option should only be used with decoupled projects. More details, visit 13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 14 | # org.gradle.parallel=true 15 | #Sat Aug 01 11:01:50 GMT+05:30 2015 16 | STATUS=release 17 | REPO_KEY=libs-release-local 18 | //RELEASE=CONFIG 19 | ARTIFACTORY_GROUP=com.flipkart.circularImage 20 | ARTIFACTORY_REPO_URL=http\://artifactory.nm.flipkart.com\:8081/artifactory 21 | org.gradle.jvmargs=-Xmx2048m -XX\:MaxPermSize\=512m -XX\:+HeapDumpOnOutOfMemoryError -Dfile.encoding\=UTF-8 22 | VERSION_NAME=1.0.2 23 | VERSION_CODE=1 24 | -------------------------------------------------------------------------------- /circularImageLibrary/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 19 | 20 | ARTIFACTORY_REPO_URL=http://artifactory.nm.flipkart.com:8081/artifactory 21 | ARTIFACTORY_GROUP=com.flipkart.circularImage 22 | VERSION_CODE=1 23 | 24 | //RELEASE CONFIG 25 | REPO_KEY=libs-release-local 26 | VERSION_NAME=1.0.22 27 | STATUS=release 28 | -------------------------------------------------------------------------------- /circularImageLibrary/src/main/java/com/flipkart/circularImageView/TextDrawer.java: -------------------------------------------------------------------------------- 1 | package com.flipkart.circularImageView; 2 | 3 | import android.graphics.Color; 4 | 5 | /** 6 | * Holds the information to draw a text. 7 | *

8 | * Created by vivek.soneja on 22/02/15. 9 | */ 10 | public class TextDrawer { 11 | private String text; 12 | private int backgroundColor; 13 | private int textColor; 14 | 15 | public TextDrawer() { 16 | backgroundColor = Color.BLUE; 17 | textColor = Color.WHITE; 18 | } 19 | 20 | //Setters 21 | public TextDrawer setText(String text) { 22 | this.text = text; 23 | return this; 24 | } 25 | 26 | public TextDrawer setBackgroundColor(int color) { 27 | this.backgroundColor = color; 28 | return this; 29 | } 30 | 31 | public TextDrawer setTextColor(int color) { 32 | this.textColor = color; 33 | return this; 34 | } 35 | 36 | //Getters 37 | public int getBackgroundColor() { 38 | return backgroundColor; 39 | } 40 | 41 | public int getTextColor() { 42 | return textColor; 43 | } 44 | 45 | public String getText() { 46 | return text; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /circularImageLibrary/src/main/java/com/flipkart/circularImageView/notification/RectangularNotificationDrawer.java: -------------------------------------------------------------------------------- 1 | package com.flipkart.circularImageView.notification; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Rect; 5 | import android.graphics.RectF; 6 | 7 | /** 8 | * Draws Rectangular Notification 9 | * Created by vivek.soneja on 23/04/15. 10 | */ 11 | public class RectangularNotificationDrawer extends NotificationDrawer { 12 | @Override 13 | public void draw(Canvas canvas, Rect outerBounds, float notificationCenterX, float notificationCenterY) { 14 | //Adjust notificationCenterY so that it shall not go out of bounds 15 | float effectiveHeight = mNotificationBounds.height() + mNotificationPadding * 2; 16 | if (notificationCenterY - effectiveHeight / 2 < outerBounds.top) notificationCenterY = outerBounds.top + effectiveHeight / 2; 17 | else if (notificationCenterY + effectiveHeight / 2 > outerBounds.bottom) notificationCenterY = outerBounds.bottom - effectiveHeight / 2; 18 | RectF rectf = new RectF(notificationCenterX - mNotificationBounds.width() / 2 - mNotificationPadding, notificationCenterY - mNotificationBounds 19 | .height() / 2 - mNotificationPadding, notificationCenterX + mNotificationBounds.width() / 2 + mNotificationPadding, notificationCenterY + 20 | mNotificationBounds.height() / 2 + mNotificationPadding); 21 | canvas.drawRoundRect(rectf, mNotificationTextPaint.getTextSize() * 0.15f, mNotificationTextPaint.getTextSize() * 0.15f, mNotificationPaint); 22 | 23 | canvas.drawText(mNotificationText, 0, mNotificationText.length(), notificationCenterX, notificationCenterY - (mNotificationTextPaint.ascent() + 24 | mNotificationTextPaint.descent()) / 2, mNotificationTextPaint); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /circularImageLibrary/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 10 | 13 | 14 | 19 | 20 | 25 | 26 | 31 | 32 | 37 | 38 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /circularImageLibrary/src/main/java/com/flipkart/circularImageView/notification/CircularNotificationDrawer.java: -------------------------------------------------------------------------------- 1 | package com.flipkart.circularImageView.notification; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Rect; 5 | 6 | /** 7 | * Draws circular notification drawer 8 | * Created by vivek.soneja on 23/04/15. 9 | */ 10 | public class CircularNotificationDrawer extends NotificationDrawer { 11 | private Float radius; 12 | private Float textSize; 13 | 14 | public CircularNotificationDrawer setNotificationSize(float radius, float textSize) { 15 | this.radius = radius; 16 | this.textSize = textSize; 17 | return this; 18 | } 19 | 20 | @Override 21 | public void draw(Canvas canvas, Rect outerBounds, float notificationCenterX, float notificationCenterY) { 22 | if (outerBounds == null) return; 23 | 24 | //Adjust notificationCenterY so that it shall not go out of bounds 25 | float effectiveWidth = getEffectiveWidth(); 26 | 27 | if (notificationCenterY - effectiveWidth / 2 < outerBounds.top) notificationCenterY = outerBounds.top + effectiveWidth / 2; 28 | else if (notificationCenterY + effectiveWidth / 2 > outerBounds.bottom) notificationCenterY = outerBounds.bottom - effectiveWidth / 2; 29 | 30 | if (notificationCenterX + effectiveWidth / 2 > outerBounds.right) notificationCenterX = outerBounds.right - effectiveWidth / 2; 31 | else if (notificationCenterX - effectiveWidth / 2 < outerBounds.left) notificationCenterX = outerBounds.left + effectiveWidth / 2; 32 | 33 | canvas.drawCircle(notificationCenterX, notificationCenterY, effectiveWidth / 2, mNotificationPaint); 34 | 35 | prepareNotificationTextPaint(); 36 | 37 | canvas.drawText(mNotificationText, 0, mNotificationText.length(), notificationCenterX, notificationCenterY - (mNotificationTextPaint.ascent() + 38 | mNotificationTextPaint.descent()) / 2, mNotificationTextPaint); 39 | } 40 | 41 | private void prepareNotificationTextPaint() { 42 | if (textSize != null) mNotificationTextPaint.setTextSize(textSize); 43 | } 44 | 45 | private float getEffectiveWidth() { 46 | if (radius == null) return mNotificationBounds.width() + mNotificationPadding * 2; 47 | else return 2 * radius; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CircularImage 2 | 3 | ####Getting it 4 | Step 1: Add this in your root build.gradle at the end of repositories: 5 | ``` 6 | allprojects { 7 | repositories { 8 | ... 9 | maven { url "https://jitpack.io" } 10 | } 11 | } 12 | ``` 13 | Step 2: Add the dependency 14 | ``` 15 | dependencies { 16 | compile 'com.github.flipkart-incubator:circular-image:1.0' 17 | } 18 | ``` 19 | 20 | ####Description 21 | CircularImage is an android library to create a configurable CircularDrawables. It has the following functionalities: 22 | 23 | 1. Combines upto 4 bitmaps to create one combined CircularDrawable. Additionally, it supports combination of 2 and 3 bitmaps. 24 | 2. Supports drawing of text, if bitmaps are not available. 25 | 3. Supports drawing of different types of configurable notifications, at any random angle x from horizontal. 26 | 4. Supports badges at a fixed position. 27 | 5. Supports configurable dividers and borders. 28 | 6. Optimised to reduce overdraw. 29 | 30 | ####Screenshot 31 | ![Alt text](/Screenshots/Screenshot_2015-05-14-18-24-34.png?raw=true "Screenshot") ![Alt text](/Screenshots/Screenshot_overdraw.png?raw=true "Screenshot Overdraw") 32 | 33 | ####Sample Code 34 | ``` 35 | CircularDrawable circularDrawable = new CircularDrawable(); 36 | circularDrawable.setBitmapOrText(bitmap1, bitmap2); 37 | //Set Notification 38 | circularDrawable.setNotificationDrawer(new CircularNotificationDrawer().setNotificationText("51").setNotificationAngle(135).setNotificationColor(Color.WHITE, Color.RED)); 39 | //Set Divider 40 | circularDrawable.setDivider(4, Color.WHITE); 41 | circularDrawable.setBadge(badgeIcon); 42 | circularDrawable.setBorder(Color.BLACK, 4); 43 | //Set the drawable to imageView 44 | imageView.setImageDrawable(circularDrawable) 45 | //Set the overlay arc 46 | circularDrawable10.setOverlayArcDrawer(new OverlayArcDrawer(Color.parseColor("#BB333333"), 30, 120)); 47 | ``` 48 | 49 | For more details, please refer the sample application. 50 | 51 | 52 | ###Creating a chat head : example 53 | ``` 54 | Random rnd = new Random(); 55 | int randomColor = Color.argb(255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256)); 56 | CircularDrawable circularDrawable = new CircularDrawable(); 57 | circularDrawable.setBitmapOrTextOrIcon(new TextDrawer().setText("C"+key).setBackgroundColor(randomColor)); 58 | int badgeCount = (int) (Math.random() * 10f); 59 | circularDrawable.setNotificationDrawer(new CircularNotificationDrawer().setNotificationText(String.valueOf(badgeCount)).setNotificationAngle(135).setNotificationColor(Color.WHITE, Color.RED)); 60 | circularDrawable.setBorder(Color.WHITE, 3); 61 | ``` 62 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /circularImageLibrary/src/main/java/com/flipkart/circularImageView/OverlayArcDrawer.java: -------------------------------------------------------------------------------- 1 | package com.flipkart.circularImageView; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapShader; 5 | import android.graphics.Matrix; 6 | import android.graphics.Paint; 7 | import android.graphics.Rect; 8 | import android.graphics.Shader; 9 | 10 | /** 11 | * Drawer for overlay arc 12 | * Created by vivek.soneja on 04/12/15. 13 | */ 14 | public class OverlayArcDrawer { 15 | private BitmapShader overlayShader; 16 | private Paint mPaint; 17 | private Bitmap bitmap; 18 | private int startAngle; 19 | private int swipeAngle; 20 | 21 | public OverlayArcDrawer(int color, int startAngle, int swipeAngle) { 22 | this.startAngle = startAngle; 23 | this.swipeAngle = swipeAngle; 24 | 25 | mPaint = new Paint(); 26 | mPaint.setAntiAlias(true); 27 | mPaint.setDither(true); 28 | mPaint.setColor(color); 29 | mPaint.setStyle(Paint.Style.FILL); 30 | } 31 | 32 | public OverlayArcDrawer(Bitmap bitmap, int startAngle, int swipeAngle) { 33 | this.bitmap = bitmap; 34 | this.startAngle = startAngle; 35 | this.swipeAngle = swipeAngle; 36 | 37 | mPaint = new Paint(); 38 | mPaint.setAntiAlias(true); 39 | mPaint.setDither(true); 40 | mPaint.setStyle(Paint.Style.FILL); 41 | overlayShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); 42 | mPaint.setShader(overlayShader); 43 | } 44 | 45 | public void setBounds(Rect bounds) { 46 | if (overlayShader != null) { 47 | Matrix matrix = new Matrix(); 48 | double scaley, scalex; 49 | if (swipeAngle % 360 > 180) { 50 | int angle = 90 - (swipeAngle % 360 - 180) / 2; 51 | double radians = Math.toRadians(angle); 52 | double desiredHeight = bounds.height() / 2 + bounds.height() * Math.sin(radians) / 2; 53 | scaley = desiredHeight / bitmap.getHeight(); 54 | } else { 55 | int angle = 90 - (swipeAngle % 360) / 2; 56 | double radians = Math.toRadians(angle); 57 | double desiredHeight = bounds.height() / 2 - bounds.height() * Math.sin(radians) / 2; 58 | scaley = desiredHeight / bitmap.getHeight(); 59 | } 60 | 61 | if((double)bitmap.getWidth() * scaley >= bounds.width()) { 62 | scalex = scaley; 63 | } else { 64 | scalex = (double)bounds.width() / (double) bitmap.getWidth(); 65 | } 66 | 67 | matrix.setScale((float) scalex, (float) scaley); 68 | matrix.postTranslate(bounds.left, bounds.top); 69 | System.out.println(matrix.toShortString()); 70 | // matrix.setTranslate(0, 0); 71 | overlayShader.setLocalMatrix(matrix); 72 | } 73 | } 74 | 75 | public Paint getPaint() { 76 | return mPaint; 77 | } 78 | 79 | public int getStartAngle() { 80 | return startAngle; 81 | } 82 | 83 | public int getSwipeAngle() { 84 | return swipeAngle; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /circularImageLibrary/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion "22.0.1" 6 | 7 | defaultConfig { 8 | minSdkVersion 14 9 | targetSdkVersion 21 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile fileTree(dir: 'libs', include: ['*.jar']) 23 | compile 'com.android.support:appcompat-v7:22.0.0' 24 | } 25 | 26 | buildscript { 27 | repositories { 28 | jcenter() 29 | maven { url 'http://repo1.maven.org/maven2' } 30 | maven { url 'http://artifactory.nm.flipkart.com:8081/artifactory/libs-release-local' } 31 | } 32 | 33 | dependencies { 34 | classpath 'com.android.tools.build:gradle:2.2.0-alpha1' 35 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3' 36 | classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:2.2.3' 37 | } 38 | } 39 | 40 | 41 | group = ARTIFACTORY_GROUP 42 | version = VERSION_NAME 43 | status = STATUS 44 | 45 | apply plugin: 'artifactory' 46 | apply plugin: 'com.github.dcendents.android-maven' 47 | 48 | configurations { 49 | published 50 | } 51 | 52 | task sourceJar(type: Jar) { 53 | from 'src/main/java' 54 | classifier "sources" 55 | } 56 | 57 | artifactoryPublish { 58 | dependsOn sourceJar 59 | } 60 | 61 | artifacts { 62 | published sourceJar 63 | } 64 | 65 | configure(install.repositories.mavenInstaller) { 66 | pom.project { 67 | licenses { 68 | license { 69 | name 'The Apache Software License, Version 2.0' 70 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt' 71 | distribution 'repo' 72 | } 73 | } 74 | } 75 | } 76 | 77 | task wrapper(type: Wrapper) { 78 | gradleVersion = '2.2.1' 79 | } 80 | 81 | artifactory { 82 | contextUrl = ARTIFACTORY_REPO_URL 83 | publish { 84 | repository { 85 | repoKey = REPO_KEY //The Artifactory repository key to publish to 86 | //username = artifactory_user //The publisher user name, property taken from gradle.properties 87 | //password = artifactory_password //The publisher password, property taken from gradle.properties 88 | } 89 | defaults { 90 | publishConfigs('archives', 'published') 91 | properties = ['build.status': "$it.project.status".toString()] 92 | publishPom = true //Publish generated POM files to Artifactory (true by default) 93 | publishIvy = false //Publish generated Ivy descriptor files to Artifactory (true by default) 94 | } 95 | } 96 | resolve { 97 | repository { 98 | repoKey = REPO_KEY //The Artifactory (preferably virtual) repository key to resolve from 99 | //username = artifactory_user //Optional resolver user name (leave out to use anonymous resolution), property taken from gradle.properties 100 | //password = artifactory_password //The resolver password, property taken from gradle.properties 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 14 | 17 | 18 | 23 | 24 | 29 | 30 | 35 | 36 | 41 | 42 | 47 | 48 | 53 | 54 | 59 | 60 | 65 | 66 | 71 | 72 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /circularImageLibrary/src/main/java/com/flipkart/circularImageView/notification/NotificationDrawer.java: -------------------------------------------------------------------------------- 1 | package com.flipkart.circularImageView.notification; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Color; 5 | import android.graphics.Paint; 6 | import android.graphics.Rect; 7 | import android.graphics.RectF; 8 | 9 | /** 10 | * Draws notification 11 | * Created by vivek.soneja on 23/04/15. 12 | */ 13 | @SuppressWarnings("unused") 14 | public abstract class NotificationDrawer { 15 | private float mNotificationCenterX; 16 | private float mNotificationCenterY; 17 | private Rect outerBounds; 18 | protected float mNotificationPadding; //Pixels 19 | protected float mNotificationHeight; //Pixels 20 | protected float mNotificationWidth; //Pixels 21 | protected double mNotificationAngleFromHorizontal; //Radians 22 | protected Rect mNotificationBounds; 23 | protected final Paint mNotificationPaint; 24 | protected String mNotificationText; 25 | protected final Paint mNotificationTextPaint; 26 | 27 | public NotificationDrawer() { 28 | mNotificationPaint = new Paint(); 29 | mNotificationPaint.setAntiAlias(true); 30 | mNotificationPaint.setDither(true); 31 | mNotificationPaint.setColor(Color.RED); 32 | 33 | mNotificationTextPaint = new Paint(); 34 | mNotificationTextPaint.setColor(Color.WHITE); 35 | mNotificationTextPaint.setTextSize(90); 36 | mNotificationTextPaint.setLinearText(true); 37 | mNotificationTextPaint.setAntiAlias(true); 38 | mNotificationTextPaint.setDither(true); 39 | mNotificationTextPaint.setTextAlign(Paint.Align.CENTER); 40 | 41 | this.mNotificationAngleFromHorizontal = 0.785; //Radians (45 Degrees) 42 | mNotificationBounds = new Rect(); 43 | } 44 | 45 | /** 46 | * Show the notification ticker text 47 | * 48 | * @param notificationText Text to be shown 49 | */ 50 | public NotificationDrawer setNotificationText(String notificationText) { 51 | this.mNotificationText = notificationText; 52 | return this; 53 | } 54 | 55 | /** 56 | * Set Notification Angle from horizontal 57 | * 58 | * @param notificationAngle angle from horizontal (in Degree). 59 | */ 60 | public NotificationDrawer setNotificationAngle(int notificationAngle) { 61 | this.mNotificationAngleFromHorizontal = 3.14 * notificationAngle / 180; 62 | return this; 63 | } 64 | 65 | /** 66 | * Set notification background Color 67 | * 68 | * @param textColor Text color 69 | * @param backgroundColor Background color 70 | */ 71 | public NotificationDrawer setNotificationColor(int textColor, int backgroundColor) { 72 | mNotificationPaint.setColor(backgroundColor); 73 | mNotificationTextPaint.setColor(textColor); 74 | return this; 75 | } 76 | 77 | public void drawNotification(Canvas canvas) { 78 | draw(canvas, outerBounds, mNotificationCenterX, mNotificationCenterY); 79 | } 80 | 81 | public void onBoundsChange(Rect bounds, float borderWidth) { 82 | outerBounds = bounds; 83 | mNotificationTextPaint.setTextSize((bounds.height() - 2 * borderWidth) * 0.4f * 0.65f); 84 | mNotificationPadding = mNotificationTextPaint.getTextSize() * 0.3f; 85 | 86 | int notificationTextLength = mNotificationText.length(); 87 | float textSize = mNotificationTextPaint.getTextSize(); 88 | mNotificationTextPaint.getTextBounds(mNotificationText, 0, notificationTextLength, mNotificationBounds); 89 | mNotificationCenterX = (float) (bounds.centerX() + (bounds.width() / 2) * Math.cos(mNotificationAngleFromHorizontal)); 90 | //Adjust notificationCenterX so that it shall not go out of bounds 91 | float effectiveWidth = mNotificationBounds.width() + mNotificationPadding * 2; 92 | if (mNotificationCenterX + effectiveWidth / 2 > bounds.right) mNotificationCenterX = bounds.right - effectiveWidth / 2; 93 | else if (mNotificationCenterX - effectiveWidth / 2 < bounds.left) mNotificationCenterX = bounds.left + effectiveWidth / 2; 94 | 95 | mNotificationCenterY = (float) (bounds.centerY() - (bounds.width() / 2) * Math.sin(mNotificationAngleFromHorizontal)); 96 | } 97 | 98 | public abstract void draw(Canvas canvas, Rect outerBounds, float centerX, float centerY); 99 | } 100 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /circularImageLibrary/src/main/java/com/flipkart/circularImageView/IconMatrixGenerator.java: -------------------------------------------------------------------------------- 1 | package com.flipkart.circularImageView; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Matrix; 5 | import android.graphics.RectF; 6 | import android.widget.ImageView; 7 | 8 | /** 9 | * Generate a Matrix to transform the given bitmap to desired destination. 10 | *

11 | * Created by vivek.soneja on 18/02/15. 12 | */ 13 | public class IconMatrixGenerator { 14 | private RectF mRect; 15 | private float mBorderWidth; 16 | private float mPadding; 17 | 18 | public Matrix generateMatrix(ImageView.ScaleType scaleType, Bitmap bitmap, DrawerHelper.DrawingType drawingType, boolean translateVertically) { 19 | Matrix matrix = new Matrix(); 20 | switch (scaleType) { 21 | case CENTER_CROP: 22 | switch (drawingType) { 23 | case QUARTER_CIRCLE: 24 | setMatrixForQuarterCircle(matrix, bitmap, drawingType); 25 | break; 26 | case HALF_CIRCLE: 27 | setMatrixForHalfCircle(matrix, bitmap, drawingType, translateVertically); 28 | break; 29 | case FULL_CIRCLE: 30 | setMatrixForFullCircle(matrix, bitmap, translateVertically); 31 | break; 32 | } 33 | } 34 | return matrix; 35 | } 36 | 37 | public IconMatrixGenerator(RectF mRect, float mBorderWidth, float mPadding) { 38 | this.mRect = mRect; 39 | this.mBorderWidth = mBorderWidth; 40 | this.mPadding = mPadding; 41 | } 42 | 43 | private void setMatrixForHalfCircle(Matrix matrix, Bitmap bitmap, DrawerHelper.DrawingType drawingType, boolean translateVertically) { 44 | float scale; 45 | if (bitmap.getWidth() < bitmap.getHeight()) { 46 | //Portrait 47 | scale = (mRect.width() - 2 * mPadding) / bitmap.getWidth(); 48 | matrix.setScale(scale, scale); 49 | 50 | float shift; 51 | if(drawingType.getPosition() == 1) shift = (bitmap.getWidth() * scale - mRect.width() / 2) * -1 / 2; 52 | else shift = (bitmap.getWidth() * scale - mRect.width() / 2) / 2; 53 | 54 | //Portrait we don't want to translate to middle, since most of the faces are in top area, not in center 55 | matrix.postTranslate(mRect.left + shift + mBorderWidth, mRect.top + mBorderWidth); 56 | } else { 57 | //Landscape 58 | scale = (mRect.width() / 2 - 2 * mPadding)/ bitmap.getWidth(); 59 | float difference; 60 | if (drawingType.getPosition() == 1) difference = (bitmap.getWidth() * scale - mRect.width() / 2) * -1 / 2 + mBorderWidth; 61 | else difference = (bitmap.getWidth() * scale - 3 * mRect.width() / 2) * -1 / 2 + mBorderWidth; 62 | 63 | float dy = 0; 64 | if(translateVertically) { 65 | float verticalDifference = mRect.height() - bitmap.getHeight() * scale; 66 | dy = verticalDifference / 2; 67 | } 68 | 69 | matrix.setScale(scale, scale); 70 | matrix.postTranslate(mRect.left + difference, mRect.top + mBorderWidth + dy); 71 | } 72 | } 73 | 74 | private void setMatrixForFullCircle(Matrix matrix, Bitmap bitmap, boolean translateVertically) { 75 | float scale; 76 | if (bitmap.getHeight() > bitmap.getWidth()) { 77 | //Portrait 78 | scale = (mRect.width() - 2 * mPadding)/ bitmap.getWidth(); 79 | matrix.setScale(scale, scale); 80 | 81 | float dy = 0; 82 | if(translateVertically) { 83 | float difference = mRect.height() - bitmap.getHeight() * scale; 84 | dy = difference / 2; 85 | } 86 | 87 | matrix.setScale(scale, scale); 88 | matrix.postTranslate(mRect.left, mRect.top + dy); 89 | } else { 90 | //Landscape 91 | scale = (mRect.height() - 2 * mPadding)/ bitmap.getHeight(); 92 | float difference = mRect.width() - bitmap.getWidth() * scale; 93 | 94 | float dy = 0; 95 | if(translateVertically) { 96 | float verticalDifference = mRect.height() - bitmap.getHeight() * scale; 97 | dy = verticalDifference / 2; 98 | } 99 | 100 | matrix.setScale(scale, scale); 101 | matrix.postTranslate(mRect.left + difference / 2, mRect.top + dy); 102 | } 103 | } 104 | 105 | @SuppressWarnings("SuspiciousNameCombination") 106 | private void setMatrixForQuarterCircle(Matrix matrix, Bitmap bitmap, DrawerHelper.DrawingType drawingType) { 107 | float delta = mRect.width()/2 - mRect.width()/(2 * 1.414f); 108 | float scale; 109 | if (bitmap.getHeight() > bitmap.getWidth()) { 110 | //Portrait 111 | scale = (mRect.width() - 2 * mPadding) / (2 * bitmap.getWidth()); 112 | matrix.setScale(scale, scale); 113 | //Portrait we don't want to translate to middle, since most of the faces are in top area, not in center 114 | float translateX = 0, translateY = 0; 115 | switch (drawingType.getPosition()) { 116 | case 1: 117 | translateX = mBorderWidth + 100; 118 | translateY = mBorderWidth + 100; 119 | break; 120 | 121 | case 2: 122 | translateX = mBorderWidth; 123 | translateY = mRect.height() / 2 + mBorderWidth; 124 | break; 125 | 126 | case 3: 127 | translateX = mRect.width() / 2 + mBorderWidth; 128 | translateY = mBorderWidth; 129 | break; 130 | 131 | case 4: 132 | translateX = mRect.width() / 2 + mBorderWidth; 133 | translateY = mBorderWidth + mRect.height() / 2; 134 | break; 135 | } 136 | matrix.postTranslate(mRect.left +translateX,mRect.top + translateY); 137 | } else { 138 | //Landscape 139 | scale = (mRect.height() / (2 * 1.414f) - 2 * mPadding) / ( bitmap.getHeight()); 140 | float translateX = 0, translateY = 0; 141 | switch (drawingType.getPosition()) { 142 | case 1: 143 | translateX = mPadding + delta; 144 | translateY = mBorderWidth + delta + mPadding; 145 | break; 146 | 147 | case 2: 148 | translateX = mPadding + delta; 149 | translateY = mRect.height() / 2 + mBorderWidth + mPadding; 150 | break; 151 | 152 | case 3: 153 | translateX = mPadding + mRect.width() / 2; 154 | translateY = mBorderWidth + mPadding + delta; 155 | break; 156 | 157 | case 4: 158 | translateX = mPadding + mRect.width() / 2; 159 | translateY = mBorderWidth + mPadding + mRect.height() / 2; 160 | break; 161 | } 162 | 163 | matrix.setScale(scale, scale); 164 | matrix.postTranslate(mRect.left + translateX, mRect.top + translateY); 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /circularImageLibrary/src/main/java/com/flipkart/circularImageView/MatrixGenerator.java: -------------------------------------------------------------------------------- 1 | package com.flipkart.circularImageView; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Matrix; 5 | import android.graphics.RectF; 6 | import android.widget.ImageView; 7 | 8 | /** 9 | * Generate a Matrix to transform the given bitmap to desired destination. 10 | *

11 | * Created by vivek.soneja on 18/02/15. 12 | */ 13 | public class MatrixGenerator { 14 | private RectF mRect; 15 | private float mBorderWidth; 16 | 17 | public MatrixGenerator(RectF mRect, float mBorderWidth) { 18 | this.mRect = mRect; 19 | this.mBorderWidth = mBorderWidth; 20 | } 21 | 22 | public Matrix generateMatrix(ImageView.ScaleType scaleType, Bitmap bitmap, DrawerHelper.DrawingType drawingType) { 23 | Matrix matrix = new Matrix(); 24 | switch (scaleType) { 25 | case CENTER_CROP: 26 | switch (drawingType) { 27 | case QUARTER_CIRCLE: 28 | setMatrixForQuarterCircle(matrix, bitmap, drawingType); 29 | break; 30 | case HALF_CIRCLE: 31 | setMatrixForHalfCircle(matrix, bitmap, drawingType); 32 | break; 33 | case FULL_CIRCLE: 34 | setMatrixForFullCircle(scaleType, matrix, bitmap); 35 | break; 36 | } 37 | break; 38 | case FIT_CENTER: 39 | setMatrixForFullCircle(scaleType, matrix, bitmap); 40 | break; 41 | } 42 | return matrix; 43 | } 44 | 45 | //noinspection SuspiciousNameCombination 46 | private void setMatrixForHalfCircle(Matrix matrix, Bitmap bitmap, DrawerHelper.DrawingType drawingType) { 47 | float scale; 48 | if (bitmap.getWidth() < bitmap.getHeight()) { 49 | //Portrait 50 | scale = mRect.width() / bitmap.getWidth(); 51 | matrix.setScale(scale, scale); 52 | 53 | float shift; 54 | if (drawingType.getPosition() == 1) 55 | shift = (bitmap.getWidth() * scale - mRect.width() / 2) * -1 / 2; 56 | else shift = (bitmap.getWidth() * scale - mRect.width() / 2) / 2; 57 | 58 | //Portrait we don't want to translate to middle, since most of the faces are in top area, not in center 59 | matrix.postTranslate(mRect.left + shift + mBorderWidth, mRect.top + mBorderWidth); 60 | } else { 61 | //Landscape 62 | scale = mRect.height() / bitmap.getHeight(); 63 | float difference; 64 | if (drawingType.getPosition() == 1) 65 | difference = (bitmap.getWidth() * scale - mRect.width() / 2) * -1 / 2 + mBorderWidth; 66 | else 67 | difference = (bitmap.getWidth() * scale - 3 * mRect.width() / 2) * -1 / 2 + mBorderWidth; 68 | matrix.setScale(scale, scale); 69 | matrix.postTranslate(mRect.left + difference, mRect.top + mBorderWidth); 70 | } 71 | } 72 | 73 | private void setMatrixForFullCircle(ImageView.ScaleType scaleType, Matrix matrix, Bitmap bitmap) { 74 | float scale; 75 | if (scaleType == ImageView.ScaleType.CENTER_CROP) { 76 | if (bitmap.getHeight() > bitmap.getWidth()) { 77 | //Portrait 78 | scale = (mRect.width()) / bitmap.getWidth(); 79 | matrix.setScale(scale, scale); 80 | //Portrait we don't want to translate to middle, since most of the faces are in top area, not in center 81 | matrix.setScale(scale, scale); 82 | matrix.postTranslate(mRect.left, mRect.top); 83 | } else { 84 | //Landscape 85 | scale = (mRect.height()) / bitmap.getHeight(); 86 | float difference = mRect.width() - bitmap.getWidth() * scale; 87 | matrix.setScale(scale, scale); 88 | matrix.postTranslate(mRect.left + difference / 2, mRect.top); 89 | } 90 | } else if (scaleType == ImageView.ScaleType.FIT_CENTER) { 91 | RectF bitmapRect = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight()); 92 | float divisor = 1.414f; //sqrt of 2 because inner square fitting inside circle has a side of circle's diameter divided by sqrt(2) 93 | float sideDimension = (Math.max(mRect.width(), mRect.height()) / divisor); // side of the inner square 94 | float remainingSpace = (Math.max(mRect.width(), mRect.height()) - sideDimension); // empty space used for center aligning 95 | RectF newRect = new RectF(mRect.left + (remainingSpace / 2f), mRect.top + (remainingSpace / 2f), mRect.left + (remainingSpace / 2f) + sideDimension, mRect.top + (remainingSpace / 2f) + sideDimension); 96 | matrix.setRectToRect(bitmapRect, newRect, Matrix.ScaleToFit.CENTER); 97 | } 98 | } 99 | 100 | 101 | @SuppressWarnings("SuspiciousNameCombination") 102 | private void setMatrixForQuarterCircle(Matrix matrix, Bitmap bitmap, DrawerHelper.DrawingType drawingType) { 103 | float scale; 104 | if (bitmap.getHeight() > bitmap.getWidth()) { 105 | //Portrait 106 | scale = mRect.width() / (2 * bitmap.getWidth()); 107 | matrix.setScale(scale, scale); 108 | //Portrait we don't want to translate to middle, since most of the faces are in top area, not in center 109 | float translateX = 0, translateY = 0; 110 | switch (drawingType.getPosition()) { 111 | case 1: 112 | translateX = mBorderWidth; 113 | translateY = mBorderWidth; 114 | break; 115 | 116 | case 2: 117 | translateX = mBorderWidth; 118 | translateY = mRect.height() / 2 + mBorderWidth; 119 | break; 120 | 121 | case 3: 122 | translateX = mRect.width() / 2 + mBorderWidth; 123 | translateY = mBorderWidth; 124 | break; 125 | 126 | case 4: 127 | translateX = mRect.width() / 2 + mBorderWidth; 128 | translateY = mBorderWidth + mRect.height() / 2; 129 | break; 130 | } 131 | matrix.postTranslate(mRect.left + translateX, mRect.top + translateY); 132 | } else { 133 | //Landscape 134 | scale = mRect.height() / (2 * bitmap.getHeight()); 135 | float translateX = 0, translateY = 0; 136 | switch (drawingType.getPosition()) { 137 | case 1: 138 | translateX = (mRect.width() / 2 + 2 * mBorderWidth - bitmap.getWidth() * scale) / 2; 139 | translateY = mBorderWidth; 140 | break; 141 | 142 | case 2: 143 | translateX = (mRect.width() / 2 + 2 * mBorderWidth - bitmap.getWidth() * scale) / 2; 144 | translateY = mRect.height() / 2 + mBorderWidth; 145 | break; 146 | 147 | case 3: 148 | translateX = (3 * mRect.width() / 2 + 2 * mBorderWidth - bitmap.getWidth() * scale) / 2; 149 | translateY = mBorderWidth; 150 | break; 151 | 152 | case 4: 153 | translateX = (3 * mRect.width() / 2 + 2 * mBorderWidth - bitmap.getWidth() * scale) / 2; 154 | translateY = mBorderWidth + mRect.height() / 2; 155 | break; 156 | } 157 | 158 | matrix.setScale(scale, scale); 159 | matrix.postTranslate(mRect.left + translateX, mRect.top + translateY); 160 | } 161 | } 162 | 163 | public Matrix generateMatrix(RectF containerRect, RectF badgeRect, Bitmap bitmap) { 164 | Matrix matrix = new Matrix(); 165 | float scale; 166 | if (bitmap.getHeight() > bitmap.getWidth()) { 167 | //Portrait 168 | scale = badgeRect.width() / bitmap.getWidth(); 169 | matrix.setScale(scale, scale); 170 | //Portrait we don't want to translate to middle, since most of the faces are in top area, not in center 171 | matrix.setScale(scale, scale); 172 | matrix.postTranslate(containerRect.left + mBorderWidth + containerRect.width() - badgeRect.width(), containerRect.top + mBorderWidth + containerRect.height() - badgeRect.height()); 173 | } else { 174 | //Landscape 175 | scale = badgeRect.height() / bitmap.getHeight(); 176 | float difference = badgeRect.width() + 2 * mBorderWidth - bitmap.getWidth() * scale; 177 | matrix.setScale(scale, scale); 178 | matrix.postTranslate(containerRect.left + difference / 2 + containerRect.width() - badgeRect.width(), containerRect.top + mBorderWidth + containerRect.height() - badgeRect.height()); 179 | } 180 | return matrix; 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /app/src/main/java/com/flipkart/sample/circularImage/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.flipkart.sample.circularImage; 2 | 3 | import android.app.ProgressDialog; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.graphics.Color; 7 | import android.graphics.drawable.Drawable; 8 | import android.graphics.drawable.InsetDrawable; 9 | import android.graphics.drawable.LayerDrawable; 10 | import android.os.AsyncTask; 11 | import android.os.Bundle; 12 | import android.support.v7.app.ActionBarActivity; 13 | import android.util.Log; 14 | import android.util.TypedValue; 15 | import android.widget.ImageView; 16 | 17 | import com.flipkart.circularImageView.BitmapDrawer; 18 | import com.flipkart.circularImageView.CircularDrawable; 19 | import com.flipkart.circularImageView.IconDrawer; 20 | import com.flipkart.circularImageView.OverlayArcDrawer; 21 | import com.flipkart.circularImageView.TextDrawer; 22 | import com.flipkart.circularImageView.notification.CircularNotificationDrawer; 23 | import com.flipkart.circularImageView.notification.RectangularNotificationDrawer; 24 | 25 | 26 | public class MainActivity extends ActionBarActivity { 27 | 28 | @Override 29 | protected void onCreate(Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | setContentView(R.layout.activity_main); 32 | 33 | new ImageLoader().execute(); 34 | } 35 | 36 | private class ImageLoader extends AsyncTask { 37 | private CircularDrawable circularDrawable1; 38 | private CircularDrawable circularDrawable2; 39 | private CircularDrawable circularDrawable3; 40 | private CircularDrawable circularDrawable4; 41 | private CircularDrawable circularDrawable5; 42 | private CircularDrawable circularDrawable6; 43 | private CircularDrawable circularDrawable7; 44 | private CircularDrawable circularDrawable8; 45 | private CircularDrawable circularDrawable9; 46 | private CircularDrawable circularDrawable10; 47 | private CircularDrawable circularDrawable11; 48 | private ProgressDialog loadingDialog; 49 | 50 | @Override 51 | protected void onPreExecute() { 52 | super.onPreExecute(); 53 | loadingDialog = ProgressDialog.show(MainActivity.this, null, "Loading"); 54 | } 55 | 56 | @Override 57 | protected Void doInBackground(Void... params) { 58 | Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.jennifer_aniston); 59 | Bitmap bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.katrina_kaif); 60 | Bitmap shopFrontBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.seller_icon); 61 | Bitmap badgeIcon = BitmapFactory.decodeResource(getResources(), R.drawable.flipkart_round); 62 | Log.v(MainActivity.class.getName(), "Height:" + bitmap1.getHeight() + " Width:" + bitmap1.getWidth()); 63 | 64 | //Test Image 1 65 | circularDrawable1 = new CircularDrawable(); 66 | BitmapDrawer bitmapDrawer = new BitmapDrawer(); 67 | bitmapDrawer.bitmap = bitmap1; 68 | bitmapDrawer.scaleType = ImageView.ScaleType.CENTER_CROP; 69 | circularDrawable1.setBitmapOrTextOrIcon(bitmapDrawer); 70 | circularDrawable1.setNotificationDrawer(new CircularNotificationDrawer().setNotificationSize(36, 52).setNotificationText("5") 71 | .setNotificationAngle(45).setNotificationColor(Color.BLACK, Color.parseColor("#FDC301"))); 72 | circularDrawable1.setBadge(badgeIcon); 73 | // circularDrawable1.setNotificationSize(50, 50, 50, 3); 74 | circularDrawable1.setBorder(Color.TRANSPARENT, 12); 75 | 76 | //Test Image 2 77 | circularDrawable2 = new CircularDrawable(); 78 | BitmapDrawer bitmapDrawer2 = new BitmapDrawer(); 79 | bitmapDrawer2.bitmap = bitmap2; 80 | bitmapDrawer2.scaleType = ImageView.ScaleType.FIT_CENTER; 81 | circularDrawable2.setBitmapOrTextOrIcon(bitmapDrawer2); 82 | circularDrawable2.setNotificationDrawer(new RectangularNotificationDrawer().setNotificationText("5").setNotificationAngle(45)); 83 | // circularDrawable2.setNotificationStyle(CircularDrawable.NotificationStyle.Circle); 84 | // circularDrawable2.setNotificationColor(Color.BLACK, Color.parseColor("#FDC301")); 85 | circularDrawable2.setBadge(badgeIcon); 86 | circularDrawable2.setBorder(Color.BLACK, 4); 87 | 88 | //Test Image 10 89 | circularDrawable10 = new CircularDrawable(); 90 | circularDrawable10.setBitmapOrTextOrIcon(bitmap2); 91 | circularDrawable10.setNotificationDrawer(new RectangularNotificationDrawer().setNotificationText("5").setNotificationAngle(45)); 92 | // circularDrawable10.setBadge(badgeIcon); 93 | circularDrawable10.setBorder(Color.BLACK, 4); 94 | circularDrawable10.setOverlayArcDrawer(new OverlayArcDrawer(Color.parseColor("#BB333333"), 30, 120)); 95 | 96 | //Test Image 3 97 | circularDrawable3 = new CircularDrawable(); 98 | TextDrawer vsTextDrawer = new TextDrawer().setText("VS").setBackgroundColor(Color.BLUE).setTextColor(Color.WHITE); 99 | circularDrawable3.setBitmapOrTextOrIcon(vsTextDrawer); 100 | circularDrawable3.setOverlayArcDrawer(new OverlayArcDrawer(shopFrontBitmap, 210, 120)); 101 | circularDrawable3.setBadge(badgeIcon); 102 | // circularDrawable3.setBorder(Color.BLACK, 4); 103 | 104 | //Test Image 11 105 | circularDrawable11 = new CircularDrawable(); 106 | TextDrawer vsTextDrawer1 = new TextDrawer().setText("VS").setBackgroundColor(Color.BLUE).setTextColor(Color.WHITE); 107 | circularDrawable11.setBitmapOrTextOrIcon(vsTextDrawer1); 108 | circularDrawable11.setBadge(badgeIcon); 109 | circularDrawable11.setOverlayArcDrawer(new OverlayArcDrawer(shopFrontBitmap, 210, 120)); 110 | // circularDrawable3.setBorder(Color.BLACK, 4); 111 | 112 | //Test Image 4 113 | circularDrawable4 = new CircularDrawable(); 114 | circularDrawable4.setBitmapOrTextOrIcon(bitmap1, bitmap2); 115 | circularDrawable4.setNotificationDrawer(new CircularNotificationDrawer().setNotificationText("51").setNotificationAngle(135).setNotificationColor 116 | (Color.WHITE, Color.RED)); 117 | circularDrawable4.setDivider(4, Color.WHITE); 118 | // circularDrawable4.setBadge(badgeIcon); 119 | // circularDrawable4.setBorder(Color.BLACK, 4); 120 | 121 | //Test Image 5 122 | circularDrawable5 = new CircularDrawable(); 123 | circularDrawable5.setBitmapOrTextOrIcon(vsTextDrawer, bitmap2, bitmap1); 124 | circularDrawable5.setDivider(4, Color.WHITE); 125 | // circularDrawable5.setBadge(badgeIcon); 126 | circularDrawable5.setBorder(Color.MAGENTA, 8); 127 | 128 | //Test Image 6 129 | circularDrawable6 = new CircularDrawable(); 130 | TextDrawer abTextDrawer = new TextDrawer().setText("AB").setBackgroundColor(Color.RED).setTextColor(Color.WHITE); 131 | circularDrawable6.setBitmapOrTextOrIcon(vsTextDrawer, bitmap2, bitmap1, abTextDrawer); 132 | circularDrawable6.setDivider(4, Color.WHITE); 133 | // circularDrawable6.setNotificationText("5"); 134 | // circularDrawable6.setNotificationAngle(135); 135 | // circularDrawable6.setNotificationStyle(CircularDrawable.NotificationStyle.Circle); 136 | // circularDrawable6.setNotificationColor(Color.WHITE, Color.RED); 137 | // circularDrawable6.setBadge(badgeIcon); 138 | // circularDrawable6.setBorder(Color.BLUE, 8); 139 | 140 | circularDrawable7 = new CircularDrawable(); 141 | IconDrawer iconDrawer = new IconDrawer(BitmapFactory.decodeResource(getResources(), R.drawable.profile_placeholder), Color.BLACK).setMargin(pxFromDp(15)); 142 | circularDrawable7.setBitmapOrTextOrIcon(iconDrawer); 143 | 144 | circularDrawable8 = new CircularDrawable(); 145 | iconDrawer = new IconDrawer(BitmapFactory.decodeResource(getResources(), R.drawable.profile_placeholder), Color.BLUE).setMargin(pxFromDp(6)); 146 | circularDrawable8.setBitmapOrTextOrIcon(bitmap1, iconDrawer); 147 | circularDrawable8.setDivider(4, Color.WHITE); 148 | 149 | circularDrawable9 = new CircularDrawable(); 150 | iconDrawer = new IconDrawer(BitmapFactory.decodeResource(getResources(), R.drawable.profile_placeholder), Color.BLUE).setMargin(pxFromDp(4)); 151 | circularDrawable9.setBitmapOrTextOrIcon(iconDrawer, iconDrawer, iconDrawer, iconDrawer); 152 | circularDrawable9.setDivider(4, Color.WHITE); 153 | 154 | return null; 155 | } 156 | 157 | @Override 158 | protected void onPostExecute(Void aVoid) { 159 | super.onPostExecute(aVoid); 160 | 161 | loadingDialog.dismiss(); 162 | 163 | ImageView testIcon = (ImageView) findViewById(R.id.iv_test_icon_1); 164 | testIcon.setImageDrawable(circularDrawable1); 165 | 166 | testIcon = (ImageView) findViewById(R.id.iv_test_icon_2); 167 | testIcon.setImageDrawable(circularDrawable2); 168 | 169 | testIcon = (ImageView) findViewById(R.id.iv_test_icon_3); 170 | testIcon.setImageDrawable(circularDrawable3); 171 | 172 | testIcon = (ImageView) findViewById(R.id.iv_test_icon_4); 173 | testIcon.setImageDrawable(circularDrawable4); 174 | 175 | testIcon = (ImageView) findViewById(R.id.iv_test_icon_5); 176 | testIcon.setImageDrawable(circularDrawable5); 177 | 178 | testIcon = (ImageView) findViewById(R.id.iv_test_icon_6); 179 | testIcon.setImageDrawable(circularDrawable6); 180 | 181 | testIcon = (ImageView) findViewById(R.id.iv_test_icon_7); 182 | testIcon.setImageDrawable(circularDrawable7); 183 | 184 | testIcon = (ImageView) findViewById(R.id.iv_test_icon_8); 185 | testIcon.setImageDrawable(circularDrawable8); 186 | 187 | testIcon = (ImageView) findViewById(R.id.iv_test_icon_9); 188 | testIcon.setImageDrawable(circularDrawable9); 189 | 190 | testIcon = (ImageView) findViewById(R.id.iv_test_icon_10); 191 | testIcon.setImageDrawable(circularDrawable10); 192 | 193 | testIcon = (ImageView) findViewById(R.id.iv_test_icon_11); 194 | testIcon.setImageDrawable(shadowify(circularDrawable11)); 195 | } 196 | } 197 | 198 | private float pxFromDp(int dpValue) { 199 | return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, getResources().getDisplayMetrics()); 200 | } 201 | 202 | private Drawable shadowify(Drawable drawable) { 203 | Drawable shadow = getResources().getDrawable(R.drawable.chat_bubble_shadow); 204 | InsetDrawable insetDrawable = new InsetDrawable(drawable, (int) dpToPx(20)); 205 | return new LayerDrawable(new Drawable[]{shadow, insetDrawable}); 206 | } 207 | 208 | private float dpToPx(int dp) { 209 | return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics()); 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /circularImageLibrary/src/main/java/com/flipkart/circularImageView/CircularDrawable.java: -------------------------------------------------------------------------------- 1 | package com.flipkart.circularImageView; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapShader; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.ColorFilter; 8 | import android.graphics.Matrix; 9 | import android.graphics.Paint; 10 | import android.graphics.PixelFormat; 11 | import android.graphics.Rect; 12 | import android.graphics.RectF; 13 | import android.graphics.Shader; 14 | import android.graphics.Typeface; 15 | import android.graphics.drawable.Drawable; 16 | import android.widget.ImageView; 17 | 18 | import com.flipkart.circularImageView.notification.NotificationDrawer; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | import static com.flipkart.circularImageView.DrawerHelper.DrawingType; 24 | 25 | @SuppressWarnings("unused") 26 | public class CircularDrawable extends Drawable { 27 | private static final String TAG = CircularDrawable.class.getName(); 28 | private final static boolean USE_THIN_FONT = false; 29 | 30 | private final RectF mRect; 31 | private float mBorderWidth; 32 | private int mBorderColor; 33 | private final Paint mPaint; 34 | private final Paint mBorderPaint; 35 | private final Paint mTextPaint; 36 | private final Paint mDividerPaint; 37 | 38 | private Bitmap badge; 39 | private final Paint mBadgePaint; 40 | private final RectF mBadgeRect; 41 | 42 | //Objects (Text or Bitmap) that shall be drawn in CircleDrawable 43 | private List sourceObjects = new ArrayList<>(); 44 | 45 | private ImageView.ScaleType scaleType = ImageView.ScaleType.CENTER_CROP; 46 | 47 | private NotificationDrawer notificationDrawer; 48 | private DrawerHelper drawerHelper; 49 | private OverlayArcDrawer overlayArcDrawer; 50 | 51 | private long id; 52 | private float dividerWidth; 53 | private Object tag; 54 | 55 | public enum NotificationStyle { 56 | Rectangle, Circle 57 | } 58 | 59 | public CircularDrawable() { 60 | //Initializing all the variables during construction, in order to avoid initializations during draw operation. 61 | mRect = new RectF(); 62 | mBadgeRect = new RectF(); 63 | 64 | mPaint = new Paint(); 65 | mPaint.setAntiAlias(true); 66 | mPaint.setDither(true); 67 | 68 | Paint mBackgroundPaint = new Paint(); 69 | mBackgroundPaint.setAntiAlias(true); 70 | mBackgroundPaint.setDither(true); 71 | 72 | mBorderPaint = new Paint(); 73 | mBorderPaint.setAntiAlias(true); 74 | mBorderPaint.setDither(true); 75 | mBorderPaint.setStyle(Paint.Style.STROKE); 76 | 77 | mDividerPaint = new Paint(); 78 | mDividerPaint.setAntiAlias(true); 79 | mDividerPaint.setDither(true); 80 | 81 | mBadgePaint = new Paint(); 82 | mBadgePaint.setAntiAlias(true); 83 | mBadgePaint.setDither(true); 84 | 85 | mTextPaint = new Paint(); 86 | mTextPaint.setColor(Color.WHITE); 87 | mTextPaint.setTextSize(100); 88 | mTextPaint.setLinearText(true); 89 | mTextPaint.setAntiAlias(true); 90 | mTextPaint.setDither(true); 91 | 92 | mTextPaint.setTextAlign(Paint.Align.CENTER); 93 | //Setting Thin Font space 94 | if (USE_THIN_FONT) { 95 | Typeface tf = Typeface.create("sans-serif-light", Typeface.NORMAL); 96 | mTextPaint.setTypeface(tf); 97 | } 98 | 99 | //Default border color 100 | mBorderColor = Color.BLACK; 101 | mBorderPaint.setColor(mBorderColor); 102 | 103 | drawerHelper = new DrawerHelper(mRect, mPaint, mTextPaint, mBackgroundPaint, sourceObjects); 104 | } 105 | 106 | public void setBorder(int color, float width) { 107 | mBorderWidth = width; 108 | mBorderPaint.setStrokeWidth(width); 109 | 110 | mBorderColor = color; 111 | mBorderPaint.setColor(mBorderColor); 112 | } 113 | 114 | public void setOverlayArcDrawer(OverlayArcDrawer overlayArcDrawer) { 115 | this.overlayArcDrawer = overlayArcDrawer; 116 | } 117 | 118 | /** 119 | * Provide Icon for Badge 120 | * 121 | * @param badge Icon to be used for creating a badge 122 | */ 123 | public void setBadge(Bitmap badge) { 124 | this.badge = badge; 125 | BitmapShader badgeShader = new BitmapShader(this.badge, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); 126 | mBadgePaint.setShader(badgeShader); 127 | } 128 | 129 | /** 130 | * Provide multiple Bitmaps to support 131 | * As of now we only support FOUR sources, and hence only first four will be considered. 132 | * Also, the order of drawing is same as the order of arguments. 133 | * 134 | * @param sources Either "Bitmap" or "TextDrawer" or "IconDrawer" which needs to be drawn. 135 | */ 136 | public void setBitmapOrTextOrIcon(Object... sources) throws IllegalArgumentException { 137 | sourceObjects.clear(); 138 | for (int i = 0; i < sources.length && i < 4; i++) { 139 | if (sources[i] instanceof Bitmap) { 140 | Bitmap bitmap = (Bitmap) sources[i]; 141 | BitmapDrawer drawer = new BitmapDrawer(); 142 | drawer.bitmap = bitmap; 143 | drawer.bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); 144 | sourceObjects.add(drawer); 145 | } 146 | else if (sources[i] instanceof BitmapDrawer) { 147 | BitmapDrawer drawer = (BitmapDrawer) sources[i]; 148 | drawer.bitmapShader = new BitmapShader(drawer.bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); 149 | sourceObjects.add(drawer); 150 | } 151 | else if (sources[i] instanceof TextDrawer) { 152 | sourceObjects.add(sources[i]); 153 | } else if (sources[i] instanceof IconDrawer) { 154 | sourceObjects.add(sources[i]); 155 | } else { 156 | throw new IllegalArgumentException("Arguments can either be instance of Bitmap or TextDrawer or IconDrawer"); 157 | } 158 | } 159 | } 160 | 161 | public void setDivider(float dividerWidth, int dividerColor) { 162 | this.dividerWidth = dividerWidth; 163 | this.mDividerPaint.setColor(dividerColor); 164 | } 165 | 166 | /** 167 | * Set NotificationDrawer 168 | * 169 | * @param notificationDrawer Notification Drawer 170 | */ 171 | public void setNotificationDrawer(NotificationDrawer notificationDrawer) { 172 | this.notificationDrawer = notificationDrawer; 173 | } 174 | 175 | @Override 176 | protected void onBoundsChange(Rect bounds) { 177 | super.onBoundsChange(bounds); 178 | //noinspection SuspiciousNameCombination 179 | mRect.set(bounds.left + mBorderWidth, bounds.top + mBorderWidth, bounds.right - mBorderWidth, bounds.bottom - mBorderWidth); 180 | 181 | for (int i = 0; i < sourceObjects.size(); i++) { 182 | Object sourceObject = sourceObjects.get(i); 183 | if (sourceObject instanceof BitmapDrawer) { 184 | BitmapDrawer bitmapDrawer = (BitmapDrawer) sourceObject; 185 | ImageView.ScaleType scaleType = bitmapDrawer.scaleType; 186 | bitmapDrawer.bitmapShader.setLocalMatrix(getLocalMatrix(scaleType, mRect, mBorderWidth, bitmapDrawer.bitmap, drawerHelper.getDrawingType(i, 187 | sourceObjects.size()))); 188 | } 189 | } 190 | 191 | if(overlayArcDrawer != null) { 192 | overlayArcDrawer.setBounds(bounds); 193 | } 194 | 195 | //Set Local Matrix for Shader of badge 196 | if (badge != null) { 197 | mBadgeRect.set(0, 0, mRect.width() / 2.5f, mRect.height() / 2.5f); 198 | mBadgePaint.getShader().setLocalMatrix(getLocalMatrixForBottomCorner(mRect, mBadgeRect, badge)); 199 | } 200 | 201 | //Set Text size for drawing text 202 | mTextPaint.setTextSize((bounds.height() - 2 * mBorderWidth) * 0.4f); 203 | 204 | if (this.notificationDrawer != null) 205 | notificationDrawer.onBoundsChange(bounds, mBorderWidth); 206 | 207 | } 208 | 209 | public void setId(long id) { 210 | this.id = id; 211 | } 212 | 213 | public void setTag(Object tag) { 214 | this.tag = tag; 215 | } 216 | 217 | public Object getTag() { 218 | return tag; 219 | } 220 | 221 | public long getId() { 222 | return id; 223 | } 224 | 225 | @Override 226 | public void draw(Canvas canvas) { 227 | // long currentTime = System.currentTimeMillis(); 228 | 229 | drawerHelper.drawComplexCircle(canvas); 230 | 231 | //Draw border 232 | if (mBorderWidth > 0) 233 | canvas.drawCircle(mRect.centerX(), mRect.centerY(), mRect.width() / 2 + mBorderWidth / 2 - 1, mBorderPaint); 234 | 235 | //Draw Dividers 236 | if (dividerWidth > 0f) { 237 | drawDividers(canvas); 238 | } 239 | 240 | if(overlayArcDrawer != null) { 241 | canvas.drawArc(new RectF(mRect.left, mRect.top, mRect.right, mRect.bottom), overlayArcDrawer.getStartAngle(), overlayArcDrawer.getSwipeAngle(), false, overlayArcDrawer.getPaint()); 242 | } 243 | 244 | //Draw Badge 245 | if (badge != null) { 246 | canvas.drawCircle(mRect.right - mBadgeRect.width() / 2, mRect.bottom - mBadgeRect.height() / 2, mBadgeRect.width() / 2, mBadgePaint); 247 | } 248 | 249 | //Draw Notification 250 | if (notificationDrawer != null) { 251 | notificationDrawer.drawNotification(canvas); 252 | } 253 | 254 | // if (isEnabledDebugging) Log.v("CircularImageView", "Time taken to draw: " + (System.currentTimeMillis() - currentTime) + "ms"); 255 | } 256 | 257 | private void drawDividers(Canvas canvas) { 258 | switch (sourceObjects.size()) { 259 | case 2: 260 | //Draw a vertical line 261 | canvas.drawRect(mRect.centerX() - dividerWidth / 2, mRect.top + mBorderWidth / 2, mRect.centerX() + dividerWidth / 2, mRect.bottom, 262 | mDividerPaint); 263 | break; 264 | 265 | case 3: 266 | //Draw Vertical Line 267 | canvas.drawRect(mRect.centerX() - dividerWidth / 2, mRect.top, mRect.centerX() + dividerWidth / 2, mRect.bottom, mDividerPaint); 268 | 269 | //Draw Horizontal line, from center to right end 270 | canvas.drawRect(mRect.centerX(), mRect.centerY() - dividerWidth / 2, mRect.right, mRect.centerY() + dividerWidth / 2, mDividerPaint); 271 | break; 272 | 273 | case 4: 274 | //Draw Vertical Line 275 | canvas.drawRect(mRect.centerX() - dividerWidth / 2, mRect.top, mRect.centerX() + dividerWidth / 2, mRect.bottom, mDividerPaint); 276 | 277 | //Draw Horizontal line 278 | canvas.drawRect(mRect.left, mRect.centerY() - dividerWidth / 2, mRect.right, mRect.centerY() + dividerWidth / 2, mDividerPaint); 279 | break; 280 | 281 | default: 282 | case 1: 283 | //Do Nothing, no dividers 284 | } 285 | } 286 | 287 | @Override 288 | public int getOpacity() { 289 | return PixelFormat.TRANSLUCENT; 290 | } 291 | 292 | @Override 293 | public void setAlpha(int alpha) { 294 | mPaint.setAlpha(alpha); 295 | } 296 | 297 | @Override 298 | public void setColorFilter(ColorFilter cf) { 299 | mPaint.setColorFilter(cf); 300 | } 301 | 302 | public Matrix getLocalMatrix(ImageView.ScaleType scaleType, RectF rectF, float borderWidth, Bitmap bitmap, DrawingType drawingType) { 303 | return new MatrixGenerator(rectF, borderWidth).generateMatrix(scaleType, bitmap, drawingType); 304 | } 305 | 306 | private Matrix getLocalMatrixForBottomCorner(RectF containerRect, RectF cornerRect, Bitmap badge) { 307 | return new MatrixGenerator(mRect, mBorderWidth).generateMatrix(containerRect, cornerRect, badge); 308 | } 309 | } -------------------------------------------------------------------------------- /circularImageLibrary/src/main/java/com/flipkart/circularImageView/DrawerHelper.java: -------------------------------------------------------------------------------- 1 | package com.flipkart.circularImageView; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Matrix; 5 | import android.graphics.Paint; 6 | import android.graphics.RectF; 7 | import android.widget.ImageView; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * Draws images in multiple formats (shapes) 13 | *

14 | * Created by vivek.soneja on 18/02/15. 15 | */ 16 | public class DrawerHelper { 17 | private RectF mRect; 18 | private Paint mPaint; 19 | private Paint mTextPaint; 20 | private Paint mBackgroundPaint; 21 | private List sourceObjects; 22 | 23 | public enum DrawingType { 24 | QUARTER_CIRCLE, HALF_CIRCLE, FULL_CIRCLE; 25 | 26 | int position; 27 | 28 | public DrawingType setPosition(int position) { 29 | this.position = position; 30 | return this; 31 | } 32 | 33 | public int getPosition() { 34 | return position; 35 | } 36 | } 37 | 38 | public DrawerHelper(RectF mRect, Paint mPaint, Paint mTextPaint, Paint mBackgroundPaint, List sourceObjects) { 39 | this.mRect = mRect; 40 | this.mPaint = mPaint; 41 | this.mTextPaint = mTextPaint; 42 | this.mBackgroundPaint = mBackgroundPaint; 43 | this.sourceObjects = sourceObjects; 44 | } 45 | 46 | public DrawingType getDrawingType(int position, int totalItems) { 47 | switch (totalItems) { 48 | case 4: 49 | DrawingType quarterCircle = DrawingType.QUARTER_CIRCLE; 50 | quarterCircle.setPosition(position + 1); 51 | return quarterCircle; 52 | 53 | case 3: 54 | if (position == 0) { 55 | DrawingType halfCircle = DrawingType.HALF_CIRCLE; 56 | halfCircle.setPosition(position + 1); 57 | return halfCircle; 58 | } else { 59 | DrawingType quarterCircle3 = DrawingType.QUARTER_CIRCLE; 60 | quarterCircle3.setPosition(position + 2); 61 | return quarterCircle3; 62 | } 63 | 64 | case 2: 65 | DrawingType halfCircle = DrawingType.HALF_CIRCLE; 66 | halfCircle.setPosition(position + 1); 67 | return halfCircle; 68 | 69 | default: 70 | case 1: 71 | DrawingType fullCircle = DrawingType.FULL_CIRCLE; 72 | fullCircle.setPosition(position + 1); 73 | return fullCircle; 74 | } 75 | } 76 | 77 | public void drawComplexCircle(Canvas canvas) { 78 | int size = sourceObjects.size(); 79 | for (int i = 0; i < size; i++) { 80 | Object sourceObject = sourceObjects.get(i); 81 | DrawingType drawingType = getDrawingType(i, size); 82 | switch (drawingType) { 83 | case QUARTER_CIRCLE: 84 | drawQuarter(canvas, drawingType.getPosition(), sourceObject); 85 | break; 86 | 87 | case HALF_CIRCLE: 88 | drawHalfCircle(canvas, drawingType.getPosition(), sourceObject); 89 | break; 90 | 91 | case FULL_CIRCLE: 92 | drawFullCircleImage(canvas, sourceObject); 93 | break; 94 | } 95 | } 96 | } 97 | 98 | public void drawFullCircleImage(Canvas canvas, Object sourceObject) { 99 | //Single Object, Draw one big circle of either text or image 100 | if (sourceObject instanceof BitmapDrawer) { 101 | //Its a image 102 | BitmapDrawer drawer = (BitmapDrawer) sourceObject; 103 | mPaint.setShader(drawer.bitmapShader); 104 | canvas.drawCircle(mRect.centerX(), mRect.centerY(), mRect.width() / 2, mPaint); 105 | } else if (sourceObject instanceof TextDrawer) { 106 | //Its a text, write text 107 | TextDrawer textDrawer = (TextDrawer) sourceObject; 108 | String message = textDrawer.getText(); 109 | mBackgroundPaint.setColor(textDrawer.getBackgroundColor()); 110 | mTextPaint.setColor(textDrawer.getTextColor()); 111 | canvas.drawCircle(mRect.centerX(), mRect.centerY(), mRect.width() / 2, mBackgroundPaint); 112 | canvas.drawText(message, 0, message.length() > 2 ? 2 : message.length(), mRect.centerX(), mRect.centerY() - ((mTextPaint.descent() + mTextPaint 113 | .ascent()) / 2), mTextPaint); 114 | } else if (sourceObject instanceof IconDrawer) { 115 | //Its a text, write text 116 | IconDrawer iconDrawer = (IconDrawer) sourceObject; 117 | mBackgroundPaint.setColor(iconDrawer.getBackgroundColor()); 118 | canvas.drawCircle(mRect.centerX(), mRect.centerY(), mRect.width() / 2, mBackgroundPaint); 119 | Matrix matrix = new IconMatrixGenerator(mRect, 0, iconDrawer.getMargin()).generateMatrix(ImageView.ScaleType.CENTER_CROP, iconDrawer.getIcon(), DrawingType.FULL_CIRCLE, true); 120 | canvas.drawBitmap(iconDrawer.getIcon(), matrix, null); 121 | } 122 | } 123 | 124 | /** 125 | * Draw a half circle. 126 | * 127 | * @param canvas Canvas on which half circle needs to be drawn. 128 | * @param halfNumber Which half (1 or 2) needs to be drawn 129 | */ 130 | public void drawHalfCircle(Canvas canvas, int halfNumber, Object sourceObject) { 131 | if (sourceObject instanceof BitmapDrawer) { 132 | //Its a bitmap 133 | BitmapDrawer drawer = (BitmapDrawer) sourceObject; 134 | mPaint.setShader(drawer.bitmapShader); 135 | if (halfNumber == 1) { 136 | canvas.drawArc(mRect, 90, 180, false, mPaint); 137 | } else { 138 | canvas.drawArc(mRect, 270, 180, false, mPaint); 139 | } 140 | } else if (sourceObject instanceof TextDrawer) { 141 | //Its a text 142 | TextDrawer textDrawer = (TextDrawer) sourceObject; 143 | String message = textDrawer.getText(); 144 | mBackgroundPaint.setColor(textDrawer.getBackgroundColor()); 145 | mTextPaint.setColor(textDrawer.getTextColor()); 146 | float previousTextSize = mTextPaint.getTextSize(); 147 | mTextPaint.setTextSize(previousTextSize * 0.7f); 148 | if (halfNumber == 1) { 149 | canvas.drawArc(mRect, 90, 180, false, mBackgroundPaint); 150 | canvas.drawText(message, 0, message.length() > 2 ? 2 : message.length(), mRect.centerX() - (mRect.centerX() - mRect.left) / 2, mRect.centerY 151 | () - ((mTextPaint.descent() + mTextPaint.ascent()) / 2), mTextPaint); 152 | } else { 153 | canvas.drawArc(mRect, 270, 180, false, mBackgroundPaint); 154 | canvas.drawText(message, 0, message.length() > 2 ? 2 : message.length(), mRect.centerX() + (mRect.centerX() - mRect.left) / 2, mRect.centerY 155 | () - ((mTextPaint.descent() + mTextPaint.ascent()) / 2), mTextPaint); 156 | } 157 | 158 | //Restore the textSize, once the drawing is done, so that new drawing can scale appropriately 159 | mTextPaint.setTextSize(previousTextSize); 160 | } 161 | 162 | else if (sourceObject instanceof IconDrawer) { 163 | //Its a text 164 | IconDrawer iconDrawer = (IconDrawer) sourceObject; 165 | mBackgroundPaint.setColor(iconDrawer.getBackgroundColor()); 166 | float previousTextSize = mTextPaint.getTextSize(); 167 | 168 | if (halfNumber == 1) { 169 | canvas.drawArc(mRect, 90, 180, false, mBackgroundPaint); 170 | Matrix matrix = new IconMatrixGenerator(mRect, 0, iconDrawer.getMargin()).generateMatrix(ImageView.ScaleType.CENTER_CROP, iconDrawer.getIcon(), DrawingType.HALF_CIRCLE.setPosition(1), true); 171 | canvas.drawBitmap(iconDrawer.getIcon(), matrix, null); 172 | } else { 173 | canvas.drawArc(mRect, 270, 180, false, mBackgroundPaint); 174 | Matrix matrix = new IconMatrixGenerator(mRect, 0, iconDrawer.getMargin()).generateMatrix(ImageView.ScaleType.CENTER_CROP, iconDrawer.getIcon(), DrawingType.HALF_CIRCLE.setPosition(0), true); 175 | canvas.drawBitmap(iconDrawer.getIcon(), matrix, null); 176 | } 177 | } 178 | } 179 | 180 | /** 181 | * Draws a quarter on Canvas. 182 | * 183 | * @param canvas Canvas on which quarter needs to be drawn. 184 | * @param quarterNumber Quarter number that needs to be drawn (1, 2, 3 or 4) 185 | */ 186 | private void drawQuarter(Canvas canvas, int quarterNumber, Object sourceObject) { 187 | if (sourceObject instanceof BitmapDrawer) { 188 | //Its a bitmap 189 | BitmapDrawer drawer = (BitmapDrawer) sourceObject; 190 | mPaint.setShader(drawer.bitmapShader); 191 | switch (quarterNumber) { 192 | case 1: 193 | canvas.drawArc(mRect, 180, 90, true, mPaint); 194 | break; 195 | case 2: 196 | canvas.drawArc(mRect, 90, 90, true, mPaint); 197 | break; 198 | case 3: 199 | canvas.drawArc(mRect, 270, 90, true, mPaint); 200 | break; 201 | case 4: 202 | canvas.drawArc(mRect, 0, 90, true, mPaint); 203 | break; 204 | } 205 | } else if (sourceObject instanceof TextDrawer) { 206 | //Its a text 207 | TextDrawer textDrawer = (TextDrawer) sourceObject; 208 | String message = textDrawer.getText(); 209 | mBackgroundPaint.setColor(textDrawer.getBackgroundColor()); 210 | mTextPaint.setColor(textDrawer.getTextColor()); 211 | float previousTextSize = mTextPaint.getTextSize(); 212 | mTextPaint.setTextSize(previousTextSize * 0.45f); 213 | 214 | switch (quarterNumber) { 215 | case 1: 216 | canvas.drawArc(mRect, 180, 90, true, mBackgroundPaint); 217 | canvas.drawText(message, 0, message.length() > 2 ? 2 : message.length(), mRect.centerX() - (mRect.centerX() - mRect.left) * 0.4f, mRect 218 | .centerY() - (mRect.centerY() - mRect.top) * 0.36f - ((mTextPaint.descent() + mTextPaint.ascent()) / 2), mTextPaint); 219 | break; 220 | case 2: 221 | canvas.drawArc(mRect, 90, 90, true, mBackgroundPaint); 222 | canvas.drawText(message, 0, message.length() > 2 ? 2 : message.length(), mRect.centerX() - (mRect.centerX() - mRect.left) * 0.4f, mRect 223 | .centerY() + (mRect.centerY() - mRect.top) * 0.35f - ((mTextPaint.descent() + mTextPaint.ascent()) / 2), mTextPaint); 224 | break; 225 | case 3: 226 | canvas.drawArc(mRect, 270, 90, true, mBackgroundPaint); 227 | canvas.drawText(message, 0, message.length() > 2 ? 2 : message.length(), mRect.centerX() + (mRect.centerX() - mRect.left) * 0.4f, mRect 228 | .centerY() - (mRect.centerY() - mRect.top) * 0.36f - ((mTextPaint.descent() + mTextPaint.ascent()) / 2), mTextPaint); 229 | break; 230 | case 4: 231 | canvas.drawArc(mRect, 0, 90, true, mBackgroundPaint); 232 | canvas.drawText(message, 0, message.length() > 2 ? 2 : message.length(), mRect.centerX() + (mRect.centerX() - mRect.left) * 0.4f, mRect 233 | .centerY() + (mRect.centerY() - mRect.top) * 0.35f - ((mTextPaint.descent() + mTextPaint.ascent()) / 2), mTextPaint); 234 | break; 235 | } 236 | 237 | //Restore the textSize, once the drawing is done, so that new drawing can scale appropriately 238 | mTextPaint.setTextSize(previousTextSize); 239 | } 240 | else if (sourceObject instanceof IconDrawer) { 241 | //Its a text 242 | IconDrawer iconDrawer = (IconDrawer) sourceObject; 243 | mBackgroundPaint.setColor(iconDrawer.getBackgroundColor()); 244 | 245 | switch (quarterNumber) { 246 | case 1: 247 | canvas.drawArc(mRect, 180, 90, true, mBackgroundPaint); 248 | Matrix matrix = new IconMatrixGenerator(mRect, 0, iconDrawer.getMargin()).generateMatrix(ImageView.ScaleType.CENTER_CROP, iconDrawer.getIcon(), DrawingType.QUARTER_CIRCLE.setPosition(1), true); 249 | canvas.drawBitmap(iconDrawer.getIcon(), matrix, null); 250 | break; 251 | case 2: 252 | canvas.drawArc(mRect, 90, 90, true, mBackgroundPaint); 253 | Matrix matrix1 = new IconMatrixGenerator(mRect, 0, iconDrawer.getMargin()).generateMatrix(ImageView.ScaleType.CENTER_CROP, iconDrawer.getIcon(), DrawingType.QUARTER_CIRCLE.setPosition(2), true); 254 | canvas.drawBitmap(iconDrawer.getIcon(), matrix1, null); 255 | break; 256 | case 3: 257 | canvas.drawArc(mRect, 270, 90, true, mBackgroundPaint); 258 | Matrix matrix3 = new IconMatrixGenerator(mRect, 0, iconDrawer.getMargin()).generateMatrix(ImageView.ScaleType.CENTER_CROP, iconDrawer.getIcon(), DrawingType.QUARTER_CIRCLE.setPosition(3), true); 259 | canvas.drawBitmap(iconDrawer.getIcon(), matrix3, null); 260 | break; 261 | case 4: 262 | canvas.drawArc(mRect, 0, 90, true, mBackgroundPaint); 263 | Matrix matrix4 = new IconMatrixGenerator(mRect, 0, iconDrawer.getMargin()).generateMatrix(ImageView.ScaleType.CENTER_CROP, iconDrawer.getIcon(), DrawingType.QUARTER_CIRCLE.setPosition(4), true); 264 | canvas.drawBitmap(iconDrawer.getIcon(), matrix4, null); 265 | break; 266 | } 267 | } 268 | } 269 | } 270 | --------------------------------------------------------------------------------