├── .gitignore
├── AndroidManifest.xml
├── README
├── build.properties
├── build.xml
├── default.properties
├── libs
├── gson-1.7.1.jar
├── guice-2.0-no_aop.jar
└── roboguice-1.1.2.jar
├── proguard.cfg
├── res
├── drawable-es-hdpi
│ └── icon.png
├── drawable-hdpi
│ ├── clip_2.png
│ ├── goods.png
│ ├── groupon_logo.png
│ ├── icon.png
│ ├── square_clip.png
│ ├── square_overlay.png
│ ├── user_placeholder.png
│ ├── vip_half_160.png
│ ├── vip_half_240.png
│ └── vip_half_320.png
├── drawable-ldpi
│ └── icon.png
├── drawable-mdpi
│ ├── getaway_ad.png
│ ├── icon.png
│ └── now_ad.png
├── drawable
│ ├── count_bubble.xml
│ ├── dark_button.xml
│ ├── dark_button_dn.xml
│ ├── dark_button_up.xml
│ ├── drop_shadow.9.png
│ ├── drop_shadow_root.xml
│ ├── promo_bg.xml
│ └── rounded_corners_white.xml
├── layout
│ └── main.xml
├── values-de
│ └── strings.xml
├── values-es
│ └── strings.xml
└── values
│ ├── attrs.xml
│ └── strings.xml
└── src
└── com
└── example
├── ExampleApplication.java
├── ExampleModule.java
├── MainActivity.java
├── mappers
├── IJsonMapper.java
└── JsonMapper.java
├── models
└── Foo.java
└── view
├── MaskedView.java
└── RoundedCornerImage.java
/.gitignore:
--------------------------------------------------------------------------------
1 | bin/
2 | gen/
3 | out/
4 | .DS_Store
5 | *.iws
6 | *.ipr
7 | *.iml
8 | *.ipr
9 | *.swp
10 | .idea/workspace.xml
11 | local.properties
12 | *.metadata
13 | .git/
14 | cached-robolectric-classes.jar
15 | .settings
16 | .project
17 | .classpath
18 | target/
19 | tmp/
20 | .idea
21 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | This repository houses various code samples for posts that are found on blog.donnfelker.com.
2 |
3 | Some examples include:
4 |
5 | - Rounded Corners with a drop shadow for LinearLayout
6 | - Count Bubble
7 | - GSON Mapping
8 | - and more
--------------------------------------------------------------------------------
/build.properties:
--------------------------------------------------------------------------------
1 | # This file is used to override default values used by the Ant build system.
2 | #
3 | # This file must be checked in Version Control Systems, as it is
4 | # integral to the build system of your project.
5 |
6 | # This file is only used by the Ant script.
7 |
8 | # You can use this to override default values such as
9 | # 'source.dir' for the location of your java source folder and
10 | # 'out.dir' for the location of your output folder.
11 |
12 | # You can also use it define how the release builds are signed by declaring
13 | # the following properties:
14 | # 'key.store' for the location of your keystore and
15 | # 'key.alias' for the name of the key to use.
16 | # The password will be asked during the build when you use the 'release' target.
17 |
18 |
--------------------------------------------------------------------------------
/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
27 |
28 |
29 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
42 |
54 |
55 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/default.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system use,
7 | # "build.properties", and override values to adapt the script to your
8 | # project structure.
9 |
10 | # Project target.
11 | target=android-8
12 |
--------------------------------------------------------------------------------
/libs/gson-1.7.1.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donnfelker/AndroidCodeExamples/5b1b12e3b8f4a7814ef941dc9e739df1b1842cdb/libs/gson-1.7.1.jar
--------------------------------------------------------------------------------
/libs/guice-2.0-no_aop.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donnfelker/AndroidCodeExamples/5b1b12e3b8f4a7814ef941dc9e739df1b1842cdb/libs/guice-2.0-no_aop.jar
--------------------------------------------------------------------------------
/libs/roboguice-1.1.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donnfelker/AndroidCodeExamples/5b1b12e3b8f4a7814ef941dc9e739df1b1842cdb/libs/roboguice-1.1.2.jar
--------------------------------------------------------------------------------
/proguard.cfg:
--------------------------------------------------------------------------------
1 | -optimizationpasses 5
2 | -dontusemixedcaseclassnames
3 | -dontskipnonpubliclibraryclasses
4 | -dontpreverify
5 | -verbose
6 | -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
7 |
8 | -keep public class * extends android.app.Activity
9 | -keep public class * extends android.app.Application
10 | -keep public class * extends android.app.Service
11 | -keep public class * extends android.content.BroadcastReceiver
12 | -keep public class * extends android.content.ContentProvider
13 | -keep public class * extends android.app.backup.BackupAgentHelper
14 | -keep public class * extends android.preference.Preference
15 | -keep public class com.android.vending.licensing.ILicensingService
16 |
17 | -keepclasseswithmembernames class * {
18 | native ;
19 | }
20 |
21 | -keepclasseswithmembernames class * {
22 | public (android.content.Context, android.util.AttributeSet);
23 | }
24 |
25 | -keepclasseswithmembernames class * {
26 | public (android.content.Context, android.util.AttributeSet, int);
27 | }
28 |
29 | -keepclassmembers enum * {
30 | public static **[] values();
31 | public static ** valueOf(java.lang.String);
32 | }
33 |
34 | -keep class * implements android.os.Parcelable {
35 | public static final android.os.Parcelable$Creator *;
36 | }
37 |
--------------------------------------------------------------------------------
/res/drawable-es-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donnfelker/AndroidCodeExamples/5b1b12e3b8f4a7814ef941dc9e739df1b1842cdb/res/drawable-es-hdpi/icon.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/clip_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donnfelker/AndroidCodeExamples/5b1b12e3b8f4a7814ef941dc9e739df1b1842cdb/res/drawable-hdpi/clip_2.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/goods.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donnfelker/AndroidCodeExamples/5b1b12e3b8f4a7814ef941dc9e739df1b1842cdb/res/drawable-hdpi/goods.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/groupon_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donnfelker/AndroidCodeExamples/5b1b12e3b8f4a7814ef941dc9e739df1b1842cdb/res/drawable-hdpi/groupon_logo.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donnfelker/AndroidCodeExamples/5b1b12e3b8f4a7814ef941dc9e739df1b1842cdb/res/drawable-hdpi/icon.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/square_clip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donnfelker/AndroidCodeExamples/5b1b12e3b8f4a7814ef941dc9e739df1b1842cdb/res/drawable-hdpi/square_clip.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/square_overlay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donnfelker/AndroidCodeExamples/5b1b12e3b8f4a7814ef941dc9e739df1b1842cdb/res/drawable-hdpi/square_overlay.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/user_placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donnfelker/AndroidCodeExamples/5b1b12e3b8f4a7814ef941dc9e739df1b1842cdb/res/drawable-hdpi/user_placeholder.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/vip_half_160.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donnfelker/AndroidCodeExamples/5b1b12e3b8f4a7814ef941dc9e739df1b1842cdb/res/drawable-hdpi/vip_half_160.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/vip_half_240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donnfelker/AndroidCodeExamples/5b1b12e3b8f4a7814ef941dc9e739df1b1842cdb/res/drawable-hdpi/vip_half_240.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/vip_half_320.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donnfelker/AndroidCodeExamples/5b1b12e3b8f4a7814ef941dc9e739df1b1842cdb/res/drawable-hdpi/vip_half_320.png
--------------------------------------------------------------------------------
/res/drawable-ldpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donnfelker/AndroidCodeExamples/5b1b12e3b8f4a7814ef941dc9e739df1b1842cdb/res/drawable-ldpi/icon.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/getaway_ad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donnfelker/AndroidCodeExamples/5b1b12e3b8f4a7814ef941dc9e739df1b1842cdb/res/drawable-mdpi/getaway_ad.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donnfelker/AndroidCodeExamples/5b1b12e3b8f4a7814ef941dc9e739df1b1842cdb/res/drawable-mdpi/icon.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/now_ad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donnfelker/AndroidCodeExamples/5b1b12e3b8f4a7814ef941dc9e739df1b1842cdb/res/drawable-mdpi/now_ad.png
--------------------------------------------------------------------------------
/res/drawable/count_bubble.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/res/drawable/dark_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
10 |
14 |
18 |
--------------------------------------------------------------------------------
/res/drawable/dark_button_dn.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/res/drawable/dark_button_up.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/res/drawable/drop_shadow.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donnfelker/AndroidCodeExamples/5b1b12e3b8f4a7814ef941dc9e739df1b1842cdb/res/drawable/drop_shadow.9.png
--------------------------------------------------------------------------------
/res/drawable/drop_shadow_root.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | -
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | -
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/res/drawable/promo_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/res/drawable/rounded_corners_white.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | -
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | -
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
16 |
17 |
27 |
28 |
34 |
35 |
39 |
40 |
47 |
48 |
55 |
56 |
63 |
64 |
65 |
66 |
73 |
74 |
75 |
76 |
77 |
78 |
82 |
83 |
91 |
92 |
102 |
103 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
125 |
126 |
133 |
134 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
--------------------------------------------------------------------------------
/res/values-de/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | de-ExampleCode
4 | Friend
5 |
6 |
--------------------------------------------------------------------------------
/res/values-es/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | es-Examples
4 | Amigo
5 |
6 |
--------------------------------------------------------------------------------
/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | ExampleCode
4 | Friend
5 | On the left
6 | On the right
7 | UI Examples
8 |
9 |
--------------------------------------------------------------------------------
/src/com/example/ExampleApplication.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import com.google.inject.Module;
4 | import roboguice.application.RoboApplication;
5 |
6 | import java.util.List;
7 |
8 | public class ExampleApplication extends RoboApplication {
9 |
10 | @Override
11 | protected void addApplicationModules(List modules) {
12 | modules.add( new ExampleModule() );
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/com/example/ExampleModule.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import com.example.mappers.IJsonMapper;
4 | import com.example.mappers.JsonMapper;
5 | import com.example.models.Foo;
6 | import com.google.inject.TypeLiteral;
7 | import roboguice.config.AbstractAndroidModule;
8 |
9 | public class ExampleModule extends AbstractAndroidModule {
10 |
11 |
12 | @Override
13 | protected void configure() {
14 |
15 | // Singletons
16 | bind( new TypeLiteral>(){} ).to( new TypeLiteral>(){} ).asEagerSingleton();
17 |
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/com/example/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import android.os.Bundle;
4 | import android.view.View;
5 | import android.widget.TextView;
6 | import android.widget.Toast;
7 | import roboguice.activity.RoboActivity;
8 | import roboguice.inject.InjectView;
9 |
10 | public class MainActivity extends RoboActivity
11 | {
12 |
13 | @InjectView(R.id.exampleText) protected TextView exampleText;
14 | @InjectView(R.id.bubble_button) protected TextView bubbleButton;
15 |
16 | @Override
17 | public void onCreate(Bundle savedInstanceState)
18 | {
19 | super.onCreate(savedInstanceState);
20 | setContentView(R.layout.main);
21 |
22 | exampleText.setText( R.string.friend );
23 |
24 | bubbleButton.setOnClickListener( new View.OnClickListener() {
25 | int pressedTimes = 0;
26 | @Override
27 | public void onClick(View view) {
28 | Toast.makeText(MainActivity.this, "Button was pressed! (" + (pressedTimes++) + ")", Toast.LENGTH_SHORT).show();
29 | }
30 | });
31 |
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/com/example/mappers/IJsonMapper.java:
--------------------------------------------------------------------------------
1 | package com.example.mappers;
2 |
3 | public interface IJsonMapper {
4 | TOutput mapFrom(String json);
5 | }
6 |
--------------------------------------------------------------------------------
/src/com/example/mappers/JsonMapper.java:
--------------------------------------------------------------------------------
1 | package com.example.mappers;
2 |
3 |
4 | import com.google.gson.Gson;
5 | import com.google.gson.reflect.TypeToken;
6 |
7 | import java.lang.reflect.Type;
8 |
9 | public class JsonMapper implements IJsonMapper {
10 |
11 | public TOutput mapFrom(String json) {
12 |
13 | Type type = new TypeToken(){}.getType();
14 | return new Gson().fromJson( json, type );
15 |
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/com/example/models/Foo.java:
--------------------------------------------------------------------------------
1 | package com.example.models;
2 |
3 | public class Foo {
4 | public String firstName;
5 | public String lastName;
6 | }
7 |
--------------------------------------------------------------------------------
/src/com/example/view/MaskedView.java:
--------------------------------------------------------------------------------
1 | package com.example.view;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.*;
6 | import android.graphics.drawable.BitmapDrawable;
7 | import android.graphics.drawable.Drawable;
8 | import android.util.AttributeSet;
9 | import android.view.View;
10 | import com.example.R;
11 |
12 | public class MaskedView extends View {
13 |
14 | public static final float IMAGE_BLEED_PERCENTAGE = .10f;
15 | protected Drawable maskDrawable;
16 | protected Bitmap image;
17 | protected Bitmap maskedImage;
18 | protected Bitmap overlay;
19 |
20 |
21 | protected Rect maskRect;
22 | private int maskResourceId;
23 | private int imageToMaskResourceId;
24 | private int overlayResourceId;
25 |
26 | public MaskedView(Context context, AttributeSet attrs) {
27 | super(context, attrs);
28 |
29 | init(attrs);
30 | }
31 |
32 | public MaskedView(Context context, AttributeSet attrs, int defStyle) {
33 | super(context, attrs, defStyle);
34 |
35 | init(attrs);
36 | }
37 |
38 | private void init(AttributeSet attrs) {
39 |
40 | final TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MaskedView);
41 | maskResourceId = a.getResourceId(R.styleable.MaskedView_mask, 0);
42 | maskDrawable = getResources().getDrawable(maskResourceId);
43 |
44 | imageToMaskResourceId = a.getResourceId(R.styleable.MaskedView_imageToMask, 0);
45 | image = BitmapFactory.decodeResource(getResources(), imageToMaskResourceId);
46 |
47 |
48 | }
49 |
50 | @Override
51 | protected void onDraw(Canvas canvas) {
52 | if(maskDrawable == null && image == null) return;
53 |
54 | if(maskedImage == null) {
55 | createMaskedImage(getWidth(), getHeight());
56 | }
57 |
58 | canvas.drawBitmap(maskedImage, 0, 0, null);
59 |
60 | }
61 |
62 | protected void createMaskedImage(int width, int height) {
63 |
64 | // 1. get width height of mask
65 | // 2. Scale image down to fit mask (at largest point via x or y)
66 | // 3. Center image over mask. (match centers)
67 | // 3. Apply porterduffxfermod SRC_IN to get the masked image.
68 | createMaskRect();
69 |
70 | }
71 |
72 | private void createMaskRect() {
73 |
74 | final Bitmap mask = BitmapFactory.decodeResource(getResources(), maskResourceId);
75 |
76 | int firstX = 0;
77 | int lastX = 0;
78 |
79 | int firstY = 0;
80 | int lastY = 0;
81 |
82 | int currentY = 0;
83 | int currentX = 0;
84 |
85 | int priorColor = Color.TRANSPARENT;
86 | int currentColor;
87 |
88 | int prevFirstX = 0;
89 | int prevLastX = 0;
90 | int prevFirstY = 0;
91 | int prevLastY = 0;
92 |
93 | int posY = 0;
94 | int posX = 0;
95 |
96 | // Find mask width and posY
97 | for(int y = 0; y < mask.getHeight(); y++) {
98 | currentY = y;
99 |
100 | firstX = 0;
101 | lastX = 0;
102 | for(int x = 0; x < mask.getWidth(); x++) {
103 |
104 | currentColor = mask.getPixel(x, y);
105 |
106 | if(currentColor != Color.TRANSPARENT && priorColor == Color.TRANSPARENT) {
107 | firstX = x;
108 | prevFirstX = firstX;
109 | } else if(priorColor != Color.TRANSPARENT) {
110 | lastX = x;
111 | prevLastX = lastX;
112 | }
113 |
114 | priorColor = currentColor;
115 | }
116 |
117 | if(firstX == prevFirstX && lastX == prevLastX && prevFirstX > 0 && prevLastX > 0) {
118 | firstX--;
119 | break;
120 | }
121 |
122 | }
123 |
124 | posY = currentY;
125 | int maskWidth = (lastX - firstX);
126 |
127 | //
128 | // Find mask height and posX
129 | //
130 | for(int x = 0; x < mask.getWidth(); x++) {
131 | currentX = x;
132 |
133 | for(int y = 0; y < mask.getHeight(); y++) {
134 |
135 | currentColor = mask.getPixel(x, y);
136 |
137 | if(currentColor != Color.TRANSPARENT && priorColor == Color.TRANSPARENT) {
138 | firstY = y;
139 | prevFirstY = firstY;
140 | } else if(priorColor != Color.TRANSPARENT) {
141 | lastY = y;
142 | prevLastY = lastY;
143 | }
144 |
145 | priorColor = currentColor;
146 | }
147 |
148 | if(firstY == prevFirstY && lastY == prevLastY && prevFirstY > 0 && prevLastY > 0) {
149 | break;
150 | }
151 | }
152 |
153 | posX = currentX;
154 | int maskHeight = lastY - firstY;
155 |
156 | final Rect maskRect = new Rect(posX, posY, posX + maskWidth, posY + maskHeight);
157 | Point centerOfMaskArea = new Point( maskRect.centerX(), maskRect.centerY() );
158 |
159 | //
160 | // Resize image to fit inside of mask.
161 | //
162 | int longerSideOfMask = maskRect.width() > maskRect.height() ? maskRect.width() : maskRect.height();
163 | float widthScale = ((float)longerSideOfMask / (float)image.getWidth()) + IMAGE_BLEED_PERCENTAGE;
164 | float heightScale = ((float)longerSideOfMask / (float)image.getHeight()) + IMAGE_BLEED_PERCENTAGE;
165 | int newWidth = (int) (image.getWidth() * widthScale);
166 | int newHeight = (int) (image.getHeight() * heightScale);
167 |
168 | image = Bitmap.createScaledBitmap(image, newWidth, newHeight, true);
169 |
170 |
171 |
172 | //
173 | // Center new scaled image over the mask and then porter duff mode to a new output.
174 | //
175 | Drawable imageDrawable = new BitmapDrawable(mask);
176 | Bitmap tempOutputMask = Bitmap.createBitmap(mask.getWidth(), mask.getHeight(), Bitmap.Config.ARGB_8888);
177 | Canvas canvas = new Canvas(tempOutputMask);
178 | Paint maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
179 | canvas.drawBitmap(mask, 0, 0, maskPaint);
180 |
181 | maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
182 |
183 | final Point centerOfImage = new Point(maskRect.left + (image.getWidth() / 2), maskRect.top + (image.getHeight() / 2));
184 |
185 | canvas.drawBitmap(image, maskRect.left - (centerOfImage.x - centerOfMaskArea.x ), maskRect.top - (centerOfImage.y - centerOfMaskArea.y), maskPaint);
186 |
187 |
188 | //
189 | // Merge overlay and new mask
190 | //
191 | overlay = BitmapFactory.decodeResource(getResources(), R.drawable.square_overlay);
192 |
193 | Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
194 | canvas.drawBitmap(tempOutputMask, 0, 0, p);
195 |
196 | p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER));
197 |
198 | canvas.drawBitmap(overlay, 0, 0, p);
199 | imageDrawable.draw(canvas);
200 |
201 | maskedImage = tempOutputMask;
202 | }
203 | }
204 |
--------------------------------------------------------------------------------
/src/com/example/view/RoundedCornerImage.java:
--------------------------------------------------------------------------------
1 | package com.example.view;
2 |
3 |
4 | import android.content.Context;
5 | import android.content.res.TypedArray;
6 | import android.graphics.*;
7 | import android.graphics.drawable.BitmapDrawable;
8 | import android.graphics.drawable.Drawable;
9 | import android.util.AttributeSet;
10 | import android.view.View;
11 | import com.example.R;
12 | import roboguice.util.Ln;
13 |
14 |
15 | public class RoundedCornerImage extends View {
16 |
17 | private Bitmap image;
18 | private Drawable placeholder;
19 | private Bitmap framedPhoto;
20 | private float cornerRadius;
21 |
22 |
23 | public RoundedCornerImage(Context context, AttributeSet attrs) {
24 | super(context, attrs);
25 |
26 | init(attrs);
27 | }
28 |
29 | public RoundedCornerImage(Context context, AttributeSet attrs, int defStyle) {
30 | super(context, attrs, defStyle);
31 |
32 | init(attrs);
33 |
34 | }
35 |
36 | private void init(AttributeSet attrs) {
37 | final TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.RoundedCornerImage);
38 | placeholder = getResources().getDrawable(a.getResourceId(R.styleable.RoundedCornerImage_placeHolder, 0));
39 | image = BitmapFactory.decodeResource(getResources(), a.getResourceId( R.styleable.RoundedCornerImage_image, 0));
40 | cornerRadius = a.getFloat(R.styleable.RoundedCornerImage_cornerRadius, 18); // Why default to 18? It just looks good and will actually show rounded corners.
41 | Ln.d("ROUNDED CORNER: cornerRadius:" + cornerRadius);
42 | }
43 |
44 | // Uncomment if you want to make sure that the result is always square, otherwise comment this stuff out.
45 | @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
46 | int measuredWidth = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
47 | int measuredHeight = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
48 | // Ensure this view is always square.
49 | int min = Math.min(measuredHeight, measuredWidth);
50 | setMeasuredDimension(min, min);
51 | }
52 |
53 | @Override
54 | protected void onDraw(Canvas canvas) {
55 | if(placeholder == null && image == null) return;
56 |
57 | if(framedPhoto == null) {
58 | createFramedPhoto( Math.min(getWidth(), getHeight()) );
59 | }
60 |
61 | canvas.drawBitmap(framedPhoto,0, 0, null);
62 |
63 | }
64 |
65 | private void createFramedPhoto(int size) {
66 |
67 | // Start with either the placeholder or the image. This is useful if you want to download the image and
68 | // have something showing before hand.
69 | Drawable imageDrawable = (image != null) ? new BitmapDrawable(image) : placeholder;
70 |
71 | Bitmap output = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
72 |
73 | Canvas canvas = new Canvas(output);
74 |
75 | RectF outerRect = new RectF(0, 0, size, size);
76 |
77 | /*
78 | * How To keep aspect ratio:
79 | * To base it upon the size of the image/density use the following. This is so that when the size of the image
80 | * increases, so does the size of the rounded corner. A 500 x 500 image would have a larger radius than a
81 | * 25 x 25 image would have.
82 | */
83 | //float outerRadius = size / cornerRadius;
84 |
85 | Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
86 | paint.setColor(Color.RED);
87 |
88 | canvas.drawRoundRect(outerRect, cornerRadius, cornerRadius, paint);
89 |
90 | // Compose image with red rectangle
91 | paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
92 | imageDrawable.setBounds(0, 0, size, size);
93 |
94 | // Save the layer to apply the paint
95 | canvas.saveLayer(outerRect, paint, Canvas.ALL_SAVE_FLAG);
96 | imageDrawable.draw(canvas);
97 | canvas.restore();
98 |
99 | framedPhoto = output;
100 |
101 | }
102 |
103 |
104 | }
105 |
--------------------------------------------------------------------------------