diff --git a/README.md b/README.md index 0897cfa..3a978c5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ CircleImageView =============== -A fast circular ImageView perfect for profile images. This is based on [RoundedImageView from Vince Mi](https://github.com/vinc3m1/RoundedImageView) which itself is based on [techniques recommended by Romain Guy](http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/). +A fast circular ImageView perfect for profile images. This is based on [RoundedImageView from Vince Mi](https://github.com/vinc3m1/RoundedImageView) which itself is based on techniques recommended by [Romain Guy](https://twitter.com/romainguy). ![CircleImageView](https://raw.github.com/hdodenhof/CircleImageView/master/screenshot.png) @@ -10,14 +10,14 @@ It uses a BitmapShader and **does not**: * use a clipPath (which is neither hardware accelerated nor anti-aliased) * use setXfermode to clip the bitmap (which means drawing twice to the canvas) -As this is just a custom ImaveView and not a custom Drawable or a combination of both, it can be used with all kinds of drawables, i.e. a PicassoDrawable from [Picasso](https://github.com/square/picasso) or other non-standard drawables (needs some testing though). +As this is just a custom ImageView and not a custom Drawable or a combination of both, it can be used with all kinds of drawables, i.e. a PicassoDrawable from [Picasso](https://github.com/square/picasso) or other non-standard drawables (needs some testing though). Gradle ------ ``` dependencies { ... - compile 'de.hdodenhof:circleimageview:1.1.0' + implementation 'de.hdodenhof:circleimageview:3.1.0' } ``` @@ -30,16 +30,77 @@ Usage android:layout_width="96dp" android:layout_height="96dp" android:src="@drawable/profile" - app:border_width="2dp" - app:border_color="#FF000000"/> + app:civ_border_width="2dp" + app:civ_border_color="#FF000000"/> ``` Limitations ----------- * The ScaleType is always CENTER_CROP and you'll get an exception if you try to change it. This is (currently) by design as it's perfectly fine for profile images. +* Enabling `adjustViewBounds` is not supported as this requires an unsupported ScaleType +* If you use an image loading library like Picasso or Glide, you need to disable their fade animations to avoid messed up images. For Picasso use the `noFade()` option, for Glide use `dontAnimate()`. If you want to keep the fadeIn animation, you have to fetch the image into a `Target` and apply a custom animation yourself when receiving the `Bitmap`. +* Using a `TransitionDrawable` with `CircleImageView` doesn't work properly and leads to messed up images. + +FAQ +--- +**How can I use a `VectorDrawable` with `CircleImageView`?** + +Short answer: you shouldn't. Using a `VectorDrawable` with `CircleImageView` is very inefficient. You should modify your vectors to be in a circular shape and use them with a regular ImageView instead. + +**Why doesn't `CircleImageView` extend `AppCompatImageView`?** + +Extending `AppCompatImageView` would require adding a runtime dependency for the support library without any real benefit. + +**How can I add a selector (e.g. ripple effect) bound to a circle?** + +There's currently no direct support for a circle bound selector but you can follow [these steps](https://github.com/hdodenhof/CircleImageView/issues/153#issuecomment-249692049) to implement it yourself. + +**How can I add a gap between image and border?** + +Adding a gap is also not supported directly but [there's a workaround](https://github.com/hdodenhof/CircleImageView/issues/133#issuecomment-225437930). Changelog --------- +* **3.1.0** + * Align bitmap paint flags with BitmapDrawable (improves scaling) +* **3.0.2** + * Fix NPE during initialization on API level <= 19 + * Fix wrong outline being provided if circular transformation is disabled +* **3.0.1** + * Fix touch event not fired if view is empty + * Fix touchable area limited to a circle even if transformation is disabled +* **3.0.0** + * Limit touch event handling to circle area + * Migrate to AndroidX + * Remove deprecated properties and methods +* **2.2.0** + * Add support for elevation + * Add circle background color attribute to replace fill color +* **2.1.0** + * Add support for padding + * Add option to disable circular transformation + * Fix hairline gap being drawn between image and border under some conditions + * Fix NPE when using tint attribute (which is not supported) + * Deprecate fill color as it seems to cause quite some confusion +* **2.0.0** + * BREAKING: Custom xml attributes are now prefixed with "civ_" + * Graceful handling of incompatible drawables + * Add support for a fill color shown behind images with transparent areas + * Fix dimension calculation issues with small images + * Fix bitmap not being cleared when set to null +* **1.3.0** + * Add setBorderColorResource(int resId) + * Add resource type annotations + * Add border_overlay attribute to allow drawing border on top of the base image +* **1.2.2** + * Add ColorFilter support +* **1.2.1** + * Fix ColorDrawables not being rendered properly on Lollipop +* **1.2.0** + * Add support for setImageURI(Uri uri) + * Fix view not being initialized when using CircleImageView(Context context) +* **1.1.1** + * Fix border being shown although border width is set to 0 * **1.1.0** * Add support for ColorDrawables * Add getters and setters for border color and border width @@ -51,7 +112,7 @@ Changelog License ------- - Copyright 2014 Henning Dodenhof + Copyright 2014 - 2020 Henning Dodenhof Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/build.gradle b/build.gradle index 2647a46..167a9f7 100644 --- a/build.gradle +++ b/build.gradle @@ -1,10 +1,11 @@ buildscript { repositories { - mavenCentral() + jcenter() + google() } dependencies { - classpath 'com.android.tools.build:gradle:0.7.3+' + classpath 'com.android.tools.build:gradle:3.6.1' } } @@ -13,6 +14,7 @@ allprojects { group = GROUP repositories { - mavenCentral() + jcenter() + google() } -} \ No newline at end of file +} diff --git a/circleimageview/build.gradle b/circleimageview/build.gradle index ac1d0c6..3c55fc5 100644 --- a/circleimageview/build.gradle +++ b/circleimageview/build.gradle @@ -1,13 +1,17 @@ -apply plugin: 'android-library' +apply plugin: 'com.android.library' android { - compileSdkVersion 19 - buildToolsVersion "19.0.1" + compileSdkVersion 29 + buildToolsVersion '29.0.3' defaultConfig { - minSdkVersion 9 - targetSdkVersion 19 + minSdkVersion 14 + targetSdkVersion 29 } } -apply from: 'https://raw.github.com/hdodenhof/gradle-mvn-push/master/gradle-mvn-push.gradle' \ No newline at end of file +dependencies { + compileOnly 'androidx.annotation:annotation:1.1.0' +} + +apply from: 'https://raw.github.com/hdodenhof/gradle-mvn-push/master/gradle-mvn-push.gradle' diff --git a/circleimageview/gradle.properties b/circleimageview/gradle.properties index aeb7191..657a307 100644 --- a/circleimageview/gradle.properties +++ b/circleimageview/gradle.properties @@ -1,3 +1,3 @@ POM_NAME=CircleImageView POM_ARTIFACT_ID=circleimageview -POM_PACKAGING=aar \ No newline at end of file +POM_PACKAGING=aar diff --git a/circleimageview/src/main/AndroidManifest.xml b/circleimageview/src/main/AndroidManifest.xml index 432e859..d9f621e 100644 --- a/circleimageview/src/main/AndroidManifest.xml +++ b/circleimageview/src/main/AndroidManifest.xml @@ -4,4 +4,4 @@ - \ No newline at end of file + diff --git a/circleimageview/src/main/java/de/hdodenhof/circleimageview/CircleImageView.java b/circleimageview/src/main/java/de/hdodenhof/circleimageview/CircleImageView.java index 6558957..2f27195 100644 --- a/circleimageview/src/main/java/de/hdodenhof/circleimageview/CircleImageView.java +++ b/circleimageview/src/main/java/de/hdodenhof/circleimageview/CircleImageView.java @@ -1,30 +1,63 @@ +/* + * Copyright 2014 - 2020 Henning Dodenhof + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package de.hdodenhof.circleimageview; +import android.annotation.SuppressLint; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.ColorFilter; import android.graphics.Matrix; +import android.graphics.Outline; import android.graphics.Paint; +import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Shader; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Build; import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewOutlineProvider; import android.widget.ImageView; +import androidx.annotation.ColorInt; +import androidx.annotation.ColorRes; +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +@SuppressWarnings("UnusedDeclaration") public class CircleImageView extends ImageView { private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP; private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888; - private static final int COLORDRAWABLE_DIMENSION = 1; + private static final int COLORDRAWABLE_DIMENSION = 2; private static final int DEFAULT_BORDER_WIDTH = 0; private static final int DEFAULT_BORDER_COLOR = Color.BLACK; + private static final int DEFAULT_CIRCLE_BACKGROUND_COLOR = Color.TRANSPARENT; + private static final int DEFAULT_IMAGE_ALPHA = 255; + private static final boolean DEFAULT_BORDER_OVERLAY = false; private final RectF mDrawableRect = new RectF(); private final RectF mBorderRect = new RectF(); @@ -32,23 +65,32 @@ public class CircleImageView extends ImageView { private final Matrix mShaderMatrix = new Matrix(); private final Paint mBitmapPaint = new Paint(); private final Paint mBorderPaint = new Paint(); + private final Paint mCircleBackgroundPaint = new Paint(); private int mBorderColor = DEFAULT_BORDER_COLOR; private int mBorderWidth = DEFAULT_BORDER_WIDTH; + private int mCircleBackgroundColor = DEFAULT_CIRCLE_BACKGROUND_COLOR; + private int mImageAlpha = DEFAULT_IMAGE_ALPHA; private Bitmap mBitmap; - private BitmapShader mBitmapShader; - private int mBitmapWidth; - private int mBitmapHeight; + private Canvas mBitmapCanvas; private float mDrawableRadius; private float mBorderRadius; - private boolean mReady; - private boolean mSetupPending; + private ColorFilter mColorFilter; + + private boolean mInitialized; + private boolean mRebuildShader; + private boolean mDrawableDirty; + + private boolean mBorderOverlay; + private boolean mDisableCircularTransformation; public CircleImageView(Context context) { super(context); + + init(); } public CircleImageView(Context context, AttributeSet attrs) { @@ -57,26 +99,42 @@ public CircleImageView(Context context, AttributeSet attrs) { public CircleImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - super.setScaleType(SCALE_TYPE); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0); - mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_border_width, DEFAULT_BORDER_WIDTH); - mBorderColor = a.getColor(R.styleable.CircleImageView_border_color, DEFAULT_BORDER_COLOR); + mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_civ_border_width, DEFAULT_BORDER_WIDTH); + mBorderColor = a.getColor(R.styleable.CircleImageView_civ_border_color, DEFAULT_BORDER_COLOR); + mBorderOverlay = a.getBoolean(R.styleable.CircleImageView_civ_border_overlay, DEFAULT_BORDER_OVERLAY); + mCircleBackgroundColor = a.getColor(R.styleable.CircleImageView_civ_circle_background_color, DEFAULT_CIRCLE_BACKGROUND_COLOR); a.recycle(); - mReady = true; - - if (mSetupPending) { - setup(); - mSetupPending = false; - } + init(); } - @Override - public ScaleType getScaleType() { - return SCALE_TYPE; + private void init() { + mInitialized = true; + + super.setScaleType(SCALE_TYPE); + + mBitmapPaint.setAntiAlias(true); + mBitmapPaint.setDither(true); + mBitmapPaint.setFilterBitmap(true); + mBitmapPaint.setAlpha(mImageAlpha); + mBitmapPaint.setColorFilter(mColorFilter); + + mBorderPaint.setStyle(Paint.Style.STROKE); + mBorderPaint.setAntiAlias(true); + mBorderPaint.setColor(mBorderColor); + mBorderPaint.setStrokeWidth(mBorderWidth); + + mCircleBackgroundPaint.setStyle(Paint.Style.FILL); + mCircleBackgroundPaint.setAntiAlias(true); + mCircleBackgroundPaint.setColor(mCircleBackgroundColor); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + setOutlineProvider(new OutlineProvider()); + } } @Override @@ -86,36 +144,113 @@ public void setScaleType(ScaleType scaleType) { } } + @Override + public void setAdjustViewBounds(boolean adjustViewBounds) { + if (adjustViewBounds) { + throw new IllegalArgumentException("adjustViewBounds not supported."); + } + } + + @SuppressLint("CanvasSize") @Override protected void onDraw(Canvas canvas) { - if (getDrawable() == null) { + if (mDisableCircularTransformation) { + super.onDraw(canvas); return; } - canvas.drawCircle(getWidth() / 2, getHeight() / 2, mDrawableRadius, mBitmapPaint); - canvas.drawCircle(getWidth() / 2, getHeight() / 2, mBorderRadius, mBorderPaint); + if (mCircleBackgroundColor != Color.TRANSPARENT) { + canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mCircleBackgroundPaint); + } + + if (mBitmap != null) { + if (mDrawableDirty && mBitmapCanvas != null) { + mDrawableDirty = false; + Drawable drawable = getDrawable(); + drawable.setBounds(0, 0, mBitmapCanvas.getWidth(), mBitmapCanvas.getHeight()); + drawable.draw(mBitmapCanvas); + } + + if (mRebuildShader) { + mRebuildShader = false; + + BitmapShader bitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + bitmapShader.setLocalMatrix(mShaderMatrix); + + mBitmapPaint.setShader(bitmapShader); + } + + canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mBitmapPaint); + } + + if (mBorderWidth > 0) { + canvas.drawCircle(mBorderRect.centerX(), mBorderRect.centerY(), mBorderRadius, mBorderPaint); + } + } + + @Override + public void invalidateDrawable(@NonNull Drawable dr) { + mDrawableDirty = true; + invalidate(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); - setup(); + updateDimensions(); + invalidate(); + } + + @Override + public void setPadding(int left, int top, int right, int bottom) { + super.setPadding(left, top, right, bottom); + updateDimensions(); + invalidate(); + } + + @Override + public void setPaddingRelative(int start, int top, int end, int bottom) { + super.setPaddingRelative(start, top, end, bottom); + updateDimensions(); + invalidate(); } public int getBorderColor() { return mBorderColor; } - public void setBorderColor(int borderColor) { + public void setBorderColor(@ColorInt int borderColor) { if (borderColor == mBorderColor) { return; } mBorderColor = borderColor; - mBorderPaint.setColor(mBorderColor); + mBorderPaint.setColor(borderColor); + invalidate(); + } + + public int getCircleBackgroundColor() { + return mCircleBackgroundColor; + } + + public void setCircleBackgroundColor(@ColorInt int circleBackgroundColor) { + if (circleBackgroundColor == mCircleBackgroundColor) { + return; + } + + mCircleBackgroundColor = circleBackgroundColor; + mCircleBackgroundPaint.setColor(circleBackgroundColor); invalidate(); } + /** + * @deprecated Use {@link #setCircleBackgroundColor(int)} instead + */ + @Deprecated + public void setCircleBackgroundColorResource(@ColorRes int circleBackgroundRes) { + setCircleBackgroundColor(getContext().getResources().getColor(circleBackgroundRes)); + } + public int getBorderWidth() { return mBorderWidth; } @@ -126,28 +261,117 @@ public void setBorderWidth(int borderWidth) { } mBorderWidth = borderWidth; - setup(); + mBorderPaint.setStrokeWidth(borderWidth); + updateDimensions(); + invalidate(); + } + + public boolean isBorderOverlay() { + return mBorderOverlay; + } + + public void setBorderOverlay(boolean borderOverlay) { + if (borderOverlay == mBorderOverlay) { + return; + } + + mBorderOverlay = borderOverlay; + updateDimensions(); + invalidate(); + } + + public boolean isDisableCircularTransformation() { + return mDisableCircularTransformation; + } + + public void setDisableCircularTransformation(boolean disableCircularTransformation) { + if (disableCircularTransformation == mDisableCircularTransformation) { + return; + } + + mDisableCircularTransformation = disableCircularTransformation; + + if (disableCircularTransformation) { + mBitmap = null; + mBitmapCanvas = null; + mBitmapPaint.setShader(null); + } else { + initializeBitmap(); + } + + invalidate(); } @Override public void setImageBitmap(Bitmap bm) { super.setImageBitmap(bm); - mBitmap = bm; - setup(); + initializeBitmap(); + invalidate(); } @Override public void setImageDrawable(Drawable drawable) { super.setImageDrawable(drawable); - mBitmap = getBitmapFromDrawable(drawable); - setup(); + initializeBitmap(); + invalidate(); } @Override - public void setImageResource(int resId) { + public void setImageResource(@DrawableRes int resId) { super.setImageResource(resId); - mBitmap = getBitmapFromDrawable(getDrawable()); - setup(); + initializeBitmap(); + invalidate(); + } + + @Override + public void setImageURI(Uri uri) { + super.setImageURI(uri); + initializeBitmap(); + invalidate(); + } + + @Override + public void setImageAlpha(int alpha) { + alpha &= 0xFF; + + if (alpha == mImageAlpha) { + return; + } + + mImageAlpha = alpha; + + // This might be called during ImageView construction before + // member initialization has finished on API level >= 16. + if (mInitialized) { + mBitmapPaint.setAlpha(alpha); + invalidate(); + } + } + + @Override + public int getImageAlpha() { + return mImageAlpha; + } + + @Override + public void setColorFilter(ColorFilter cf) { + if (cf == mColorFilter) { + return; + } + + mColorFilter = cf; + + // This might be called during ImageView construction before + // member initialization has finished on API level <= 19. + if (mInitialized) { + mBitmapPaint.setColorFilter(cf); + invalidate(); + } + } + + @Override + public ColorFilter getColorFilter() { + return mColorFilter; } private Bitmap getBitmapFromDrawable(Drawable drawable) { @@ -172,63 +396,117 @@ private Bitmap getBitmapFromDrawable(Drawable drawable) { drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); drawable.draw(canvas); return bitmap; - } catch (OutOfMemoryError e) { + } catch (Exception e) { + e.printStackTrace(); return null; } } - private void setup() { - if (!mReady) { - mSetupPending = true; - return; + private void initializeBitmap() { + mBitmap = getBitmapFromDrawable(getDrawable()); + + if (mBitmap != null && mBitmap.isMutable()) { + mBitmapCanvas = new Canvas(mBitmap); + } else { + mBitmapCanvas = null; } - if (mBitmap == null) { + if (!mInitialized) { return; } - mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + if (mBitmap != null) { + updateShaderMatrix(); + } else { + mBitmapPaint.setShader(null); + } + } - mBitmapPaint.setAntiAlias(true); - mBitmapPaint.setShader(mBitmapShader); + private void updateDimensions() { + mBorderRect.set(calculateBounds()); + mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2.0f, (mBorderRect.width() - mBorderWidth) / 2.0f); - mBorderPaint.setStyle(Paint.Style.STROKE); - mBorderPaint.setAntiAlias(true); - mBorderPaint.setColor(mBorderColor); - mBorderPaint.setStrokeWidth(mBorderWidth); + mDrawableRect.set(mBorderRect); + if (!mBorderOverlay && mBorderWidth > 0) { + mDrawableRect.inset(mBorderWidth - 1.0f, mBorderWidth - 1.0f); + } + mDrawableRadius = Math.min(mDrawableRect.height() / 2.0f, mDrawableRect.width() / 2.0f); - mBitmapHeight = mBitmap.getHeight(); - mBitmapWidth = mBitmap.getWidth(); + updateShaderMatrix(); + } - mBorderRect.set(0, 0, getWidth(), getHeight()); - mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2, (mBorderRect.width() - mBorderWidth) / 2); + private RectF calculateBounds() { + int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight(); + int availableHeight = getHeight() - getPaddingTop() - getPaddingBottom(); - mDrawableRect.set(mBorderWidth, mBorderWidth, mBorderRect.width() - mBorderWidth, mBorderRect.height() - mBorderWidth); - mDrawableRadius = Math.min(mDrawableRect.height() / 2, mDrawableRect.width() / 2); + int sideLength = Math.min(availableWidth, availableHeight); - updateShaderMatrix(); - invalidate(); + float left = getPaddingLeft() + (availableWidth - sideLength) / 2f; + float top = getPaddingTop() + (availableHeight - sideLength) / 2f; + + return new RectF(left, top, left + sideLength, top + sideLength); } private void updateShaderMatrix() { + if (mBitmap == null) { + return; + } + float scale; float dx = 0; float dy = 0; mShaderMatrix.set(null); - if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) { - scale = mDrawableRect.height() / (float) mBitmapHeight; - dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f; + int bitmapHeight = mBitmap.getHeight(); + int bitmapWidth = mBitmap.getWidth(); + + if (bitmapWidth * mDrawableRect.height() > mDrawableRect.width() * bitmapHeight) { + scale = mDrawableRect.height() / (float) bitmapHeight; + dx = (mDrawableRect.width() - bitmapWidth * scale) * 0.5f; } else { - scale = mDrawableRect.width() / (float) mBitmapWidth; - dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f; + scale = mDrawableRect.width() / (float) bitmapWidth; + dy = (mDrawableRect.height() - bitmapHeight * scale) * 0.5f; } mShaderMatrix.setScale(scale, scale); - mShaderMatrix.postTranslate((int) (dx + 0.5f) + mBorderWidth, (int) (dy + 0.5f) + mBorderWidth); + mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top); + + mRebuildShader = true; + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouchEvent(MotionEvent event) { + if (mDisableCircularTransformation) { + return super.onTouchEvent(event); + } + + return inTouchableArea(event.getX(), event.getY()) && super.onTouchEvent(event); + } + + private boolean inTouchableArea(float x, float y) { + if (mBorderRect.isEmpty()) { + return true; + } + + return Math.pow(x - mBorderRect.centerX(), 2) + Math.pow(y - mBorderRect.centerY(), 2) <= Math.pow(mBorderRadius, 2); + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + private class OutlineProvider extends ViewOutlineProvider { + + @Override + public void getOutline(View view, Outline outline) { + if (mDisableCircularTransformation) { + ViewOutlineProvider.BACKGROUND.getOutline(view, outline); + } else { + Rect bounds = new Rect(); + mBorderRect.roundOut(bounds); + outline.setRoundRect(bounds, bounds.width() / 2.0f); + } + } - mBitmapShader.setLocalMatrix(mShaderMatrix); } -} \ No newline at end of file +} diff --git a/circleimageview/src/main/res/values/attrs.xml b/circleimageview/src/main/res/values/attrs.xml index 2acfe65..bdfc2b1 100644 --- a/circleimageview/src/main/res/values/attrs.xml +++ b/circleimageview/src/main/res/values/attrs.xml @@ -1,7 +1,9 @@ - - + + + + - \ No newline at end of file + diff --git a/gradle.properties b/gradle.properties index f66f6f2..b65822a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -VERSION_NAME=1.1.1-SNAPSHOT +VERSION_NAME=4.0.0-SNAPSHOT GROUP=de.hdodenhof POM_DESCRIPTION=A fast circular ImageView for Android @@ -10,4 +10,7 @@ POM_LICENCE_NAME=The Apache Software License, Version 2.0 POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt POM_LICENCE_DIST=repo POM_DEVELOPER_ID=hdodenhof -POM_DEVELOPER_NAME=Henning Dodenhof \ No newline at end of file +POM_DEVELOPER_NAME=Henning Dodenhof + +android.useAndroidX=true +android.enableJetifier=false diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e4e7a74..d5e0f6f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Jan 15 21:08:12 CET 2014 +#Wed Jan 01 12:46:55 CET 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-1.9-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip diff --git a/sample/build.gradle b/sample/build.gradle index a72392c..38166e6 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -1,15 +1,15 @@ -apply plugin: 'android' +apply plugin: 'com.android.application' android { - compileSdkVersion 19 - buildToolsVersion "19.0.1" + compileSdkVersion 29 + buildToolsVersion '29.0.3' defaultConfig { minSdkVersion 14 - targetSdkVersion 19 + targetSdkVersion 29 } } dependencies { - compile project(':circleimageview') -} \ No newline at end of file + implementation project(':circleimageview') +} diff --git a/sample/proguard-rules.txt b/sample/proguard-rules.txt index 21a30b1..59985f0 100644 --- a/sample/proguard-rules.txt +++ b/sample/proguard-rules.txt @@ -14,4 +14,4 @@ # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; -#} \ No newline at end of file +#} diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index ffe9dd1..74ca48e 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -1,12 +1,16 @@ - + android:theme="@style/AppTheme" + tools:ignore="GoogleAppIndexingWarning"> + @@ -16,6 +20,7 @@ + diff --git a/sample/src/main/java/de/hdodenhof/circleimageview/sample/MainActivity.java b/sample/src/main/java/de/hdodenhof/circleimageview/sample/MainActivity.java index e2bb4e8..7875520 100644 --- a/sample/src/main/java/de/hdodenhof/circleimageview/sample/MainActivity.java +++ b/sample/src/main/java/de/hdodenhof/circleimageview/sample/MainActivity.java @@ -1,11 +1,7 @@ package de.hdodenhof.circleimageview.sample; import android.app.Activity; -import android.app.Fragment; import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; public class MainActivity extends Activity { @@ -13,25 +9,6 @@ public class MainActivity extends Activity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - - if (savedInstanceState == null) { - getFragmentManager().beginTransaction() - .add(R.id.container, new MainFragment()) - .commit(); - } - } - - public static class MainFragment extends Fragment { - - public MainFragment() { - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View rootView = inflater.inflate(R.layout.fragment_main, container, false); - return rootView; - } } } diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml index 486edff..439cf57 100644 --- a/sample/src/main/res/layout/activity_main.xml +++ b/sample/src/main/res/layout/activity_main.xml @@ -1,8 +1,42 @@ - + + + + + + + + + + + + + + + diff --git a/sample/src/main/res/layout/fragment_main.xml b/sample/src/main/res/layout/fragment_main.xml deleted file mode 100644 index 45f95da..0000000 --- a/sample/src/main/res/layout/fragment_main.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/sample/src/main/res/values/colors.xml b/sample/src/main/res/values/colors.xml index f7fe3c0..ea49b51 100644 --- a/sample/src/main/res/values/colors.xml +++ b/sample/src/main/res/values/colors.xml @@ -4,4 +4,4 @@ #FF222222 #FFEEEEEE - \ No newline at end of file + diff --git a/settings.gradle b/settings.gradle index 8fbd5fe..0503e7f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':circleimageview', ':sample' \ No newline at end of file +include ':circleimageview', ':sample'