diff --git a/cropimageview-samples/src/main/AndroidManifest.xml b/cropimageview-samples/src/main/AndroidManifest.xml
index 19500b3..2cde5b2 100644
--- a/cropimageview-samples/src/main/AndroidManifest.xml
+++ b/cropimageview-samples/src/main/AndroidManifest.xml
@@ -20,7 +20,11 @@
android:label="@string/title_activity_simple_network_crop" />
+ android:label="@string/title_activity_test" />
+
\ No newline at end of file
diff --git a/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/HomeActivity.java b/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/HomeActivity.java
index 30435dc..bd75363 100644
--- a/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/HomeActivity.java
+++ b/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/HomeActivity.java
@@ -3,6 +3,7 @@
import android.content.Intent;
import android.os.Bundle;
+import com.cesards.samples.cropimageview.rounded_corners.RoundedCornerImagesActivity;
import com.cesards.samples.cropimageview.simple_crop.SimpleCropActivity;
import com.cesards.samples.cropimageview.simple_network_crop.SimpleNetworkCropActivity;
import com.cesards.samples.cropimageview.test.TestActivity;
@@ -24,6 +25,8 @@ protected void onCreate(Bundle savedInstanceState) {
findViewById(R.id.test).setOnClickListener(view ->
startActivity(new Intent(this, TestActivity.class))
);
+ findViewById(R.id.rounded_corners).setOnClickListener(view ->
+ startActivity(new Intent(this, RoundedCornerImagesActivity.class))
+ );
}
-
}
diff --git a/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/rounded_corners/Image.java b/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/rounded_corners/Image.java
new file mode 100644
index 0000000..6882cef
--- /dev/null
+++ b/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/rounded_corners/Image.java
@@ -0,0 +1,30 @@
+package com.cesards.samples.cropimageview.rounded_corners;
+
+import com.cesards.cropimageview.crop.CropType;
+
+import androidx.annotation.DrawableRes;
+
+final class Image {
+
+ @DrawableRes private final int drawableResource;
+ private final boolean roundedCorners;
+ @CropType private final int cropType;
+
+ Image(@DrawableRes int drawableResource, boolean roundedCorners, int cropType) {
+ this.drawableResource = drawableResource;
+ this.roundedCorners = roundedCorners;
+ this.cropType = cropType;
+ }
+
+ public int drawableResource() {
+ return drawableResource;
+ }
+
+ public boolean roundedCorners() {
+ return roundedCorners;
+ }
+
+ public int cropType() {
+ return cropType;
+ }
+}
diff --git a/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/rounded_corners/ImageFactory.java b/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/rounded_corners/ImageFactory.java
new file mode 100644
index 0000000..53464df
--- /dev/null
+++ b/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/rounded_corners/ImageFactory.java
@@ -0,0 +1,92 @@
+package com.cesards.samples.cropimageview.rounded_corners;
+
+import com.cesards.cropimageview.crop.CropType;
+import com.cesards.samples.cropimageview.R;
+
+import java.util.Arrays;
+import java.util.List;
+
+final class ImageFactory {
+
+ private ImageFactory() {
+ throw new AssertionError("This shouldn't be initialized!");
+ }
+
+ static List imagesWithoutRoundedCorners() {
+ return Arrays.asList(
+// new Image(R.drawable.ball_vertical, false, CropType.NONE),
+// new Image(R.drawable.ball_horizontal, false, CropType.NONE),
+ new Image(R.drawable.ball_vertical, false, CropType.CENTER_TOP),
+ new Image(R.drawable.ball_vertical, false, CropType.CENTER_BOTTOM),
+ new Image(R.drawable.ball_horizontal, false, CropType.LEFT_TOP),
+ new Image(R.drawable.ball_horizontal, false, CropType.LEFT_CENTER),
+ new Image(R.drawable.ball_horizontal, false, CropType.LEFT_BOTTOM),
+ new Image(R.drawable.ball_horizontal, false, CropType.RIGHT_TOP),
+ new Image(R.drawable.ball_horizontal, false, CropType.RIGHT_BOTTOM),
+ new Image(R.drawable.ball_horizontal, false, CropType.RIGHT_CENTER),
+ new Image(R.drawable.ball_vertical, false, CropType.CENTER_TOP),
+ new Image(R.drawable.ball_vertical, false, CropType.CENTER_BOTTOM),
+ new Image(R.drawable.ball_horizontal, false, CropType.LEFT_TOP),
+ new Image(R.drawable.ball_horizontal, false, CropType.LEFT_CENTER),
+ new Image(R.drawable.ball_horizontal, false, CropType.LEFT_BOTTOM),
+ new Image(R.drawable.ball_horizontal, false, CropType.RIGHT_TOP),
+ new Image(R.drawable.ball_horizontal, false, CropType.RIGHT_BOTTOM),
+ new Image(R.drawable.ball_horizontal, false, CropType.RIGHT_CENTER),
+ new Image(R.drawable.ball_vertical, false, CropType.CENTER_TOP),
+ new Image(R.drawable.ball_vertical, false, CropType.CENTER_BOTTOM),
+ new Image(R.drawable.ball_horizontal, false, CropType.LEFT_TOP),
+ new Image(R.drawable.ball_horizontal, false, CropType.LEFT_CENTER),
+ new Image(R.drawable.ball_horizontal, false, CropType.LEFT_BOTTOM),
+ new Image(R.drawable.ball_horizontal, false, CropType.RIGHT_TOP),
+ new Image(R.drawable.ball_horizontal, false, CropType.RIGHT_BOTTOM),
+ new Image(R.drawable.ball_horizontal, false, CropType.RIGHT_CENTER),
+ new Image(R.drawable.ball_vertical, false, CropType.CENTER_TOP),
+ new Image(R.drawable.ball_vertical, false, CropType.CENTER_BOTTOM),
+ new Image(R.drawable.ball_horizontal, false, CropType.LEFT_TOP),
+ new Image(R.drawable.ball_horizontal, false, CropType.LEFT_CENTER),
+ new Image(R.drawable.ball_horizontal, false, CropType.LEFT_BOTTOM),
+ new Image(R.drawable.ball_horizontal, false, CropType.RIGHT_TOP),
+ new Image(R.drawable.ball_horizontal, false, CropType.RIGHT_BOTTOM),
+ new Image(R.drawable.ball_horizontal, false, CropType.RIGHT_CENTER)
+ );
+ }
+
+ static List imagesWithRoundedCorners() {
+ return Arrays.asList(
+// new Image(R.drawable.ball_vertical, false, CropType.NONE),
+// new Image(R.drawable.ball_horizontal, false, CropType.NONE),
+ new Image(R.drawable.ball_vertical, true, CropType.CENTER_TOP),
+ new Image(R.drawable.ball_vertical, true, CropType.CENTER_BOTTOM),
+ new Image(R.drawable.ball_horizontal, true, CropType.LEFT_TOP),
+ new Image(R.drawable.ball_horizontal, true, CropType.LEFT_CENTER),
+ new Image(R.drawable.ball_horizontal, true, CropType.LEFT_BOTTOM),
+ new Image(R.drawable.ball_horizontal, true, CropType.RIGHT_TOP),
+ new Image(R.drawable.ball_horizontal, true, CropType.RIGHT_BOTTOM),
+ new Image(R.drawable.ball_horizontal, true, CropType.RIGHT_CENTER),
+ new Image(R.drawable.ball_vertical, false, CropType.CENTER_TOP),
+ new Image(R.drawable.ball_vertical, false, CropType.CENTER_BOTTOM),
+ new Image(R.drawable.ball_horizontal, false, CropType.LEFT_TOP),
+ new Image(R.drawable.ball_horizontal, false, CropType.LEFT_CENTER),
+ new Image(R.drawable.ball_horizontal, false, CropType.LEFT_BOTTOM),
+ new Image(R.drawable.ball_horizontal, false, CropType.RIGHT_TOP),
+ new Image(R.drawable.ball_horizontal, false, CropType.RIGHT_BOTTOM),
+ new Image(R.drawable.ball_horizontal, false, CropType.RIGHT_CENTER),
+ new Image(R.drawable.ball_vertical, false, CropType.CENTER_TOP),
+ new Image(R.drawable.ball_vertical, false, CropType.CENTER_BOTTOM),
+ new Image(R.drawable.ball_horizontal, false, CropType.LEFT_TOP),
+ new Image(R.drawable.ball_horizontal, false, CropType.LEFT_CENTER),
+ new Image(R.drawable.ball_horizontal, false, CropType.LEFT_BOTTOM),
+ new Image(R.drawable.ball_horizontal, false, CropType.RIGHT_TOP),
+ new Image(R.drawable.ball_horizontal, false, CropType.RIGHT_BOTTOM),
+ new Image(R.drawable.ball_horizontal, false, CropType.RIGHT_CENTER),
+ new Image(R.drawable.ball_vertical, false, CropType.CENTER_TOP),
+ new Image(R.drawable.ball_vertical, false, CropType.CENTER_BOTTOM),
+ new Image(R.drawable.ball_horizontal, false, CropType.LEFT_TOP),
+ new Image(R.drawable.ball_horizontal, false, CropType.LEFT_CENTER),
+ new Image(R.drawable.ball_horizontal, false, CropType.LEFT_BOTTOM),
+ new Image(R.drawable.ball_horizontal, false, CropType.RIGHT_TOP),
+ new Image(R.drawable.ball_horizontal, false, CropType.RIGHT_BOTTOM),
+ new Image(R.drawable.ball_horizontal, false, CropType.RIGHT_CENTER)
+ );
+ }
+}
diff --git a/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/rounded_corners/ImagesAdapter.java b/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/rounded_corners/ImagesAdapter.java
new file mode 100644
index 0000000..8e70ce4
--- /dev/null
+++ b/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/rounded_corners/ImagesAdapter.java
@@ -0,0 +1,72 @@
+package com.cesards.samples.cropimageview.rounded_corners;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.cesards.cropimageview.CropImageView;
+import com.cesards.samples.cropimageview.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
+import androidx.recyclerview.widget.RecyclerView;
+
+final class ImagesAdapter extends RecyclerView.Adapter {
+
+ private final List images = new ArrayList<>();
+
+ void removeAll() {
+ if (images.isEmpty()) {
+ return;
+ }
+ int imagesLength = images.size();
+ images.clear();
+ notifyItemRangeRemoved(0, imagesLength);
+ }
+
+ void add(Image image) {
+ images.add(image);
+ notifyItemInserted(this.images.size() - 1);
+ }
+
+ void add(List images) {
+ this.images.addAll(images);
+ notifyItemRangeInserted(this.images.size() - 1, images.size());
+ }
+
+ @NonNull
+ @Override
+ public ItemImageViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ return new ItemImageViewHolder(LayoutInflater.from(
+ parent.getContext()).inflate(R.layout.item_image, parent, false)
+ );
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ItemImageViewHolder itemImageViewHolder, int position) {
+ itemImageViewHolder.bind(images.get(position));
+ }
+
+ @Override
+ public int getItemCount() {
+ return images.size();
+ }
+
+ static class ItemImageViewHolder extends RecyclerView.ViewHolder {
+
+ private final CropImageView cropImageView;
+
+ ItemImageViewHolder(@NonNull View itemView) {
+ super(itemView);
+ this.cropImageView = (CropImageView) itemView;
+ }
+
+ void bind(Image image) {
+ cropImageView.setImageDrawable(ContextCompat.getDrawable(itemView.getContext(), image.drawableResource()));
+ cropImageView.croppedImage().withCropType(image.cropType());
+ }
+ }
+}
diff --git a/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/rounded_corners/RoundedCornerImagesActivity.java b/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/rounded_corners/RoundedCornerImagesActivity.java
new file mode 100644
index 0000000..9f693bf
--- /dev/null
+++ b/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/rounded_corners/RoundedCornerImagesActivity.java
@@ -0,0 +1,77 @@
+package com.cesards.samples.cropimageview.rounded_corners;
+
+import android.os.Bundle;
+import android.app.Activity;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Spinner;
+
+import com.cesards.samples.cropimageview.R;
+import com.cesards.samples.cropimageview.rounded_corners.widget.VerticalTransparentItemDecorator;
+
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.content.ContextCompat;
+import androidx.recyclerview.widget.DividerItemDecoration;
+import androidx.recyclerview.widget.RecyclerView;
+
+public class RoundedCornerImagesActivity extends AppCompatActivity {
+
+ private ImagesAdapter imagesAdapter = new ImagesAdapter();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_rounded_corner_images);
+ setupViews(savedInstanceState);
+ }
+
+ private void setupViews(Bundle savedInstanceState) {
+ setSupportActionBar(findViewById(R.id.title_container));
+// getSupportActionBar().setHomeButtonEnabled(true);
+ getSupportActionBar().setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP);
+
+ RecyclerView images = findViewById(R.id.images);
+ images.addItemDecoration(new VerticalTransparentItemDecorator(getResources().getDimensionPixelOffset(R.dimen.activity_horizontal_margin)));
+ images.setAdapter(imagesAdapter);
+
+ Spinner navSpinner = findViewById(R.id.image_options);
+
+ navSpinner.setAdapter(
+ ArrayAdapter.createFromResource(
+ navSpinner.getContext(),
+ R.array.options,
+ android.R.layout.simple_spinner_dropdown_item
+ )
+ );
+
+ navSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView> parent, View view, int position, long id) {
+ switch (position) {
+ case 0:
+ imagesAdapter.removeAll();
+ imagesAdapter.add(ImageFactory.imagesWithoutRoundedCorners());
+ break;
+
+ case 1:
+ imagesAdapter.removeAll();
+ imagesAdapter.add(ImageFactory.imagesWithRoundedCorners());
+ break;
+
+ default:
+ throw new IllegalStateException("If it exists you can handle it.");
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> parent) { }
+ });
+
+ if (savedInstanceState == null) {
+ navSpinner.setSelection(0);
+ }
+ }
+
+}
diff --git a/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/rounded_corners/widget/VerticalTransparentItemDecorator.java b/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/rounded_corners/widget/VerticalTransparentItemDecorator.java
new file mode 100644
index 0000000..b780159
--- /dev/null
+++ b/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/rounded_corners/widget/VerticalTransparentItemDecorator.java
@@ -0,0 +1,23 @@
+package com.cesards.samples.cropimageview.rounded_corners.widget;
+
+import android.graphics.Rect;
+import android.view.View;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+public class VerticalTransparentItemDecorator extends RecyclerView.ItemDecoration {
+
+ private int space;
+
+ public VerticalTransparentItemDecorator(int value) {
+ this.space = value;
+ }
+
+ @Override
+ public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
+ // Skip first item in the list.
+ if (parent.getChildAdapterPosition(view) != 0) {
+ outRect.set(0, space, 0, 0);
+ }
+ }
+}
diff --git a/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/simple_crop/SimpleCropActivity.java b/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/simple_crop/SimpleCropActivity.java
index 046380b..1e24390 100644
--- a/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/simple_crop/SimpleCropActivity.java
+++ b/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/simple_crop/SimpleCropActivity.java
@@ -4,7 +4,7 @@
import android.view.LayoutInflater;
import android.widget.ImageView;
-import com.cesards.cropimageview.model.CropType;
+import com.cesards.cropimageview.crop.CropType;
import com.cesards.samples.cropimageview.R;
import com.cesards.samples.cropimageview._activity.CommonImagesAdapter;
import com.cesards.samples.cropimageview._util.SystemUiHelper;
@@ -54,7 +54,7 @@ public ImageView instantiatePagerItem(int position) {
// cropImageView.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ball_horizontal));
cropImageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
} else {
-// ((CropImageView) cropImageView).setCropType(images[position - 1]);
+// ((CropImageView) cropImageView).withCropType(images[position - 1]);
}
return cropImageView;
}
diff --git a/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/simple_network_crop/SimpleNetworkCropActivity.java b/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/simple_network_crop/SimpleNetworkCropActivity.java
index 4af9385..7422ecc 100644
--- a/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/simple_network_crop/SimpleNetworkCropActivity.java
+++ b/cropimageview-samples/src/main/java/com/cesards/samples/cropimageview/simple_network_crop/SimpleNetworkCropActivity.java
@@ -1,19 +1,18 @@
package com.cesards.samples.cropimageview.simple_network_crop;
import android.os.Bundle;
-import android.app.Activity;
import android.view.LayoutInflater;
import android.widget.ImageView;
import com.cesards.cropimageview.CropImageView;
-import com.cesards.cropimageview.model.CropType;
+import com.cesards.cropimageview.crop.CropType;
import com.cesards.samples.cropimageview.R;
import com.cesards.samples.cropimageview._activity.CommonImagesAdapter;
import com.cesards.samples.cropimageview._util.SystemUiHelper;
-import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso;
import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.content.ContextCompat;
import androidx.viewpager.widget.ViewPager;
public class SimpleNetworkCropActivity extends AppCompatActivity implements CommonImagesAdapter {
@@ -55,21 +54,13 @@ public ImageView instantiatePagerItem(int position) {
// cropImageView.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ball_horizontal));
if (position == 0) {
-// cropImageView.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ball_horizontal));
- cropImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
+// cropImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
+ cropImageView.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ball_horizontal));
} else {
- Picasso.get().load(R.drawable.ball_horizontal).into(cropImageView, new Callback() {
- @Override
- public void onSuccess() {
- cropImageView.setCropType(CropType.LEFT_CENTER);
- }
-
- @Override
- public void onError(Exception e) {
-
- }
- });
-// ((CropImageView) cropImageView).setCropType(images[position - 1]);
+ cropImageView.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ball_horizontal));
+// cropImageView.croppedImage().withCropType(CropType.LEFT_CENTER);
+// Picasso.get().load(R.drawable.ball_horizontal).into(cropImageView);
+// ((CropImageView) cropImageView).withCropType(images[position - 1]);
}
return cropImageView;
}
diff --git a/cropimageview-samples/src/main/res/layout/activity_home.xml b/cropimageview-samples/src/main/res/layout/activity_home.xml
index 098a6cf..64a1a5c 100644
--- a/cropimageview-samples/src/main/res/layout/activity_home.xml
+++ b/cropimageview-samples/src/main/res/layout/activity_home.xml
@@ -48,5 +48,19 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/simple_network_crop" />
+
+
\ No newline at end of file
diff --git a/cropimageview-samples/src/main/res/layout/activity_rounded_corner_images.xml b/cropimageview-samples/src/main/res/layout/activity_rounded_corner_images.xml
new file mode 100644
index 0000000..091f4ae
--- /dev/null
+++ b/cropimageview-samples/src/main/res/layout/activity_rounded_corner_images.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cropimageview-samples/src/main/res/layout/activity_test.xml b/cropimageview-samples/src/main/res/layout/activity_test.xml
index 3f2b81c..2aecd9f 100644
--- a/cropimageview-samples/src/main/res/layout/activity_test.xml
+++ b/cropimageview-samples/src/main/res/layout/activity_test.xml
@@ -4,7 +4,6 @@
android:layout_height="match_parent"
android:orientation="vertical">
-
+
\ No newline at end of file
diff --git a/cropimageview-samples/src/main/res/values/rounded_corner_options.xml b/cropimageview-samples/src/main/res/values/rounded_corner_options.xml
new file mode 100644
index 0000000..8788520
--- /dev/null
+++ b/cropimageview-samples/src/main/res/values/rounded_corner_options.xml
@@ -0,0 +1,7 @@
+
+
+
+ - Without Rounded Corners
+ - With Rounded Corners
+
+
\ No newline at end of file
diff --git a/cropimageview-samples/src/main/res/values/strings.xml b/cropimageview-samples/src/main/res/values/strings.xml
index 9e22a1f..bea659f 100644
--- a/cropimageview-samples/src/main/res/values/strings.xml
+++ b/cropimageview-samples/src/main/res/values/strings.xml
@@ -3,4 +3,5 @@
CropImageView Samples
SimpleNetworkCrop
TestActivity
+ RoundedCornerImagesActivity
diff --git a/cropimageview/src/main/java/com/cesards/cropimageview/CropImageView.java b/cropimageview/src/main/java/com/cesards/cropimageview/CropImageView.java
index c2c4d64..860d1f7 100644
--- a/cropimageview/src/main/java/com/cesards/cropimageview/CropImageView.java
+++ b/cropimageview/src/main/java/com/cesards/cropimageview/CropImageView.java
@@ -1,103 +1,184 @@
package com.cesards.cropimageview;
import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
-import android.widget.ImageView;
-import com.cesards.cropimageview.model.CropImage;
-import com.cesards.cropimageview.model.CropImageFactory;
-import com.cesards.cropimageview.model.CropType;
+import android.util.Log;
+import android.view.ViewOutlineProvider;
-import androidx.annotation.Nullable;
+import androidx.annotation.NonNull;
import androidx.appcompat.widget.AppCompatImageView;
public class CropImageView extends AppCompatImageView {
- @Nullable private CropImage cropImage;
- @CropType private int cropType = CropType.NONE;
+ private final CroppedImage croppedImage = new CroppedImage(this);
+ private final RoundedCornerImage roundedImage = new RoundedCornerImage(this);
public CropImageView(Context context) {
super(context);
- setup();
+ roundedImage.setup(context, null);
+ croppedImage.setupCrop(context, null);
}
public CropImageView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
- parseAttributes(attrs);
- setup();
+ roundedImage.setup(context, attrs);
+ croppedImage.setupCrop(context, attrs);
}
public CropImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- parseAttributes(attrs);
- setup();
+ roundedImage.setup(context, attrs);
+ croppedImage.setupCrop(context, attrs);
}
/**
- * Set crop type for the {@link ImageView}
- *
- * @param cropType A {@link CropType} desired scaling mode.
+ * Returns {@link RoundedCornerImage} so the user can retrieve and set information related to cropping
+ * the image.
*/
- public void setCropType(@CropType int cropType) {
- this.cropType = cropType;
-
- setWillNotCacheDrawing(false);
-
- requestLayout();
- invalidate();
+ @NonNull
+ public CroppedImage croppedImage() {
+ return croppedImage;
}
/**
- * Return the current crop type in use by this ImageView.
- *
- * @return a {@link CropType} in use by this ImageView
+ * Returns {@link RoundedCornerImage} so the user can retrieve and set information related to rounding
+ * the image corners.
*/
- @CropType
- public int getCropType() {
- return cropType;
- }
+// @NonNull
+// RoundedCornerImage roundedImage() {
+// return roundedImage;
+// }
@Override
protected boolean setFrame(int l, int t, int r, int b) {
final boolean changed = super.setFrame(l, t, r, b);
- if (!isInEditMode() && cropImage != null && getDrawable() != null) {
- cropImage.computeImageTransformation();
+ if (changed) {
+ croppedImage.applyTransformation();
}
+
return changed;
}
@Override
- public void setImageBitmap(Bitmap bm) {
- super.setImageBitmap(bm);
- setup();
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ Log.d("", "");
+ super.onLayout(changed, left, top, right, bottom);
+ if (changed) {
+ roundedImage.requiresShapeUpdate();
+ }
+ }
+
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ Log.d("onDraw", toString());
+ roundedImage.dispatchOnDraw(canvas);
}
+
@Override
public void setImageDrawable(Drawable drawable) {
+ Log.d("", "");
super.setImageDrawable(drawable);
- setup();
- }
+ roundedImage.requiresShapeUpdate();
- @Override
- public void setImageResource(int resId) {
- super.setImageResource(resId);
- setup();
+
+// if (drawable instanceof RoundedBitmapDrawable) {
+// super.setImageDrawable(drawable);
+// return;
+// }
+// RoundedBitmapDrawable dr = RoundedBitmapDrawableFactory.create(getResources(), ((BitmapDrawable) drawable).getBitmap());
+// mBitmapShader = new BitmapShader(dr.getBitmap(), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
+
+// dr.setCornerRadius(10f);
+// super.setImageDrawable(dr);
+// this.requiersShapeUpdate = true;
+// super.setImageDrawable(drawable);
+// postInvalidate();
}
- private void setup() {
- setScaleType(ScaleType.MATRIX);
+ @Override
+ public ViewOutlineProvider getOutlineProvider() {
+ Log.d("", "");
+// return super.getOutlineProvider();
+ return roundedImage.getOutlineProvider();
+ }
- if (getDrawable() != null) {
- cropImage = new CropImageFactory().getCropImage(this, cropType);
- }
+ @Override
+ protected void drawableStateChanged() {
+ Log.d("", "");
+ super.drawableStateChanged();
+ roundedImage.notifyDrawableStateChanges(); // is it really necessary?
}
- private void parseAttributes(AttributeSet attrs) {
- final TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.civ_CropImageView);
- cropType = a.getInt(R.styleable.civ_CropImageView_civ_crop, CropType.NONE);
- a.recycle();
+ @Override
+ public void setScaleType(ScaleType scaleType) {
+ Log.d("", "");
+ croppedImage.delegateSetScaleType(scaleType);
+// roundedImage.delegateScaleType(scaleType);
+ super.setScaleType(scaleType);
}
+
+
+
+
+
+
+
+
+
+
+// @Override
+// protected void onDraw(Canvas canvas) {
+// super.onDraw(canvas);
+// if (getDrawable() instanceof RoundedBitmapDrawable) {
+// canvas.drawRoundRect(mDstRectF, mCornerRadius, mCornerRadius, paint);
+// }
+// }
+
+
+
+
+
+
+
+
+
+ // @Override
+// public void setImageBitmap(Bitmap bm) {
+// super.setImageDrawable(roundedImage.modifiedDrawable(bm));
+// // I think it would be better not to modify this method because we are breaking Liskov principle?
+// // so we could use Bitmap modifiedBitmap(Bitmap bitmap);
+// // as
+// // super.setImageBitmap(roundedImage.modifiedBitmap(bm));
+ // bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+// }
+//
+
+// @Override
+// protected void onDraw(Canvas canvas) {
+// super.onDraw(canvas);
+// rect.bottom = getHeight();
+// rect.right = getWidth();
+// rect.left = 0;
+// rect.top = 0;
+//
+// canvas.drawRoundRect(rect, 10f, 10f, paint);
+//
+// if (requiersShapeUpdate) {
+// calculateLayout(canvas.getWidth(), canvas.getHeight());
+// requiersShapeUpdate = false;
+// }
+//
+// }
+
+
+
+
+
+
}
diff --git a/cropimageview/src/main/java/com/cesards/cropimageview/CroppedImage.java b/cropimageview/src/main/java/com/cesards/cropimageview/CroppedImage.java
new file mode 100644
index 0000000..f5814f1
--- /dev/null
+++ b/cropimageview/src/main/java/com/cesards/cropimageview/CroppedImage.java
@@ -0,0 +1,89 @@
+package com.cesards.cropimageview;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+import com.cesards.cropimageview.crop.CropType;
+import com.cesards.cropimageview.crop.ImageTransformation;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+public final class CroppedImage implements LifecycleCroppedImage {
+
+ private final ImageView imageView;
+ private final ImageTransformation imageTransformation;
+ @CropType private int cropType = CropType.NONE;
+
+ public CroppedImage(@NonNull ImageView imageView) {
+ this.imageView = imageView;
+ imageTransformation = new ImageTransformation(imageView);
+ }
+
+ /**
+ * Set crop type for the {@link ImageView}
+ *
+ * @param cropType A {@link CropType} desired scaling mode.
+ */
+ public void withCropType(@CropType int cropType) {
+ if (cropType == this.cropType) {
+ return;
+ }
+
+ this.cropType = cropType;
+ setupScaleType();
+ }
+
+ public void crop(@CropType int cropType) {
+ withCropType(cropType);
+ imageView.requestLayout();
+ imageView.invalidate();
+ }
+
+ /**
+ * Return the current crop type in use by this ImageView.
+ *
+ * @return a {@link CropType} in use by this ImageView
+ */
+ @CropType
+ public int getCropType() {
+ return cropType;
+ }
+
+ @Override
+ public void setupCrop(@NonNull Context context, @Nullable AttributeSet attributeSet) {
+ if (attributeSet != null) {
+ parseAttributes(attributeSet);
+ }
+
+ setupScaleType();
+ }
+
+ private void setupScaleType() {
+ if (cropType != CropType.NONE) {
+ imageView.setScaleType(ImageView.ScaleType.MATRIX);
+ }
+ }
+
+ @Override
+ public void applyTransformation() {
+ if (!imageView.isInEditMode() && imageView.getDrawable() != null && cropType != CropType.NONE) {
+ imageTransformation.compute(cropType);
+ }
+ }
+
+ @Override
+ public void delegateSetScaleType(ImageView.ScaleType scaleType) {
+ if (scaleType != ImageView.ScaleType.MATRIX) {
+ cropType = CropType.NONE;
+ }
+ }
+
+ private void parseAttributes(AttributeSet attrs) {
+ final TypedArray a = imageView.getContext().obtainStyledAttributes(attrs, R.styleable.civ_CropImageView);
+ cropType = a.getInt(R.styleable.civ_CropImageView_civ_crop, CropType.NONE);
+ a.recycle();
+ }
+}
diff --git a/cropimageview/src/main/java/com/cesards/cropimageview/LifecycleCroppedImage.java b/cropimageview/src/main/java/com/cesards/cropimageview/LifecycleCroppedImage.java
new file mode 100644
index 0000000..9deab70
--- /dev/null
+++ b/cropimageview/src/main/java/com/cesards/cropimageview/LifecycleCroppedImage.java
@@ -0,0 +1,18 @@
+package com.cesards.cropimageview;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+public interface LifecycleCroppedImage {
+ void setupCrop(@NonNull Context context, @Nullable AttributeSet attributeSet);
+
+ /**
+ * Call super first and return the result
+ * */
+ void applyTransformation();
+ void delegateSetScaleType(ImageView.ScaleType scaleType);
+}
diff --git a/cropimageview/src/main/java/com/cesards/cropimageview/RoundedCornerImage.java b/cropimageview/src/main/java/com/cesards/cropimageview/RoundedCornerImage.java
new file mode 100644
index 0000000..a9dd975
--- /dev/null
+++ b/cropimageview/src/main/java/com/cesards/cropimageview/RoundedCornerImage.java
@@ -0,0 +1,595 @@
+package com.cesards.cropimageview;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Outline;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+import android.widget.ImageView;
+
+import com.cesards.cropimageview.rounded_corners.ClipPathManager;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.content.res.AppCompatResources;
+import androidx.core.view.ViewCompat;
+
+public final class RoundedCornerImage implements RoundedCornerImageViewHook {
+
+
+ @NonNull private final ImageView imageView;
+ private final Paint clipPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private final Path clipPath = new Path();
+ private final PorterDuffXfermode pdMode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
+ @Nullable protected Drawable drawable = null;
+ private ClipPathManager clipManager = new ClipPathManager();
+ private boolean requiersShapeUpdate = true;
+ private Bitmap clipBitmap;
+ final Path rectView = new Path();
+ private final RectF rectF = new RectF();
+ private int topLeftRadius = 15;
+ private int topRightRadius= 15;
+ private int bottomRightRadius= 15;
+ private int bottomLeftRadius= 15;
+
+ private final RectF borderRectF = new RectF();
+ private final Path borderPath = new Path();
+
+
+ public RoundedCornerImage(@NonNull ImageView imageView) {
+ this.imageView = imageView;
+ }
+
+ @Override
+ public void setup(@NonNull Context context, @Nullable AttributeSet attributeSet) {
+ final TypedArray a = imageView.getContext().obtainStyledAttributes(attributeSet, R.styleable.civ_CropImageView);
+
+// final int cornerRadius = a.getInt(R.styleable.civ_CropImageView_civ_cornerRadius, Corner.NONE);
+// if (cornerRadius != Corner.NONE) {
+// this.cornerRadius[Corner.TOP_LEFT] = cornerRadius;
+// this.cornerRadius[Corner.TOP_RIGHT] = cornerRadius;
+// this.cornerRadius[Corner.BOTTOM_LEFT] = cornerRadius;
+// this.cornerRadius[Corner.BOTTOM_RIGHT] = cornerRadius;
+// } else {
+// this.cornerRadius[Corner.TOP_LEFT] = a.getInt(R.styleable.civ_CropImageView_civ_cornerRadiusTopLeft, Corner.NONE);
+// this.cornerRadius[Corner.TOP_RIGHT] = a.getInt(R.styleable.civ_CropImageView_civ_cornerRadiusTopRight, Corner.NONE);
+// this.cornerRadius[Corner.BOTTOM_LEFT] = a.getInt(R.styleable.civ_CropImageView_civ_cornerRadiusBottomLeft, Corner.NONE);
+// this.cornerRadius[Corner.BOTTOM_RIGHT] = a.getInt(R.styleable.civ_CropImageView_civ_cornerRadiusBottomRight, Corner.NONE);
+// }
+// for (int i = 0, len = this.cornerRadius.length; i < len; i++) {
+// if (this.cornerRadius[i] < 0) {
+// this.cornerRadius[i] = DEFAULT_RADIUS;
+// }
+// }
+
+
+ clipPaint.setAntiAlias(true);
+ imageView.setWillNotDraw(false);
+ clipPaint.setColor(Color.BLUE);
+ clipPaint.setStyle(Paint.Style.FILL);
+ clipPaint.setStrokeWidth(1);
+
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) {
+ clipPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
+ imageView.setLayerType(View.LAYER_TYPE_SOFTWARE, clipPaint); //Only works for software layers
+ } else {
+ clipPaint.setXfermode(pdMode);
+ imageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); //Only works for software layers
+ }
+
+ clipManager.setClipPathCreator(new ClipPathManager.ClipPathCreator() {
+ @Override
+ public Path createClipPath(int width, int height) {
+ rectF.set(0, 0, width, height);
+ return generatePath(rectF,
+ Math.min(topLeftRadius, Math.min(width, height)),
+ Math.min(topRightRadius, Math.min(width, height)),
+ Math.min(bottomRightRadius, Math.min(width, height)),
+ Math.min(bottomLeftRadius, Math.min(width, height))
+ );
+
+ }
+
+ @Override
+ public boolean requiresBitmap() {
+ return false;
+ }
+ });
+
+ a.recycle();
+ }
+
+ private Path generatePath(RectF rect, float topLeftRadius, float topRightRadius, float bottomRightRadius, float bottomLeftRadius) {
+ return generatePath(false, rect, topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius);
+ }
+
+ private Path generatePath(boolean useBezier, RectF rect, float topLeftRadius, float topRightRadius, float bottomRightRadius, float bottomLeftRadius) {
+ final Path path = new Path();
+
+ final float left = rect.left;
+ final float top = rect.top;
+ final float bottom = rect.bottom;
+ final float right = rect.right;
+
+ final float minSize = Math.min(rect.width() / 2f, rect.height() / 2f);
+
+ topLeftRadius = topLeftRadius < 0 ? 0 : topLeftRadius;
+ topRightRadius = topRightRadius < 0 ? 0 : topRightRadius;
+ bottomLeftRadius = bottomLeftRadius < 0 ? 0 : bottomLeftRadius;
+ bottomRightRadius = bottomRightRadius < 0 ? 0 : bottomRightRadius;
+
+ if (topLeftRadius > minSize) {
+ topLeftRadius = minSize;
+ }
+ if (topRightRadius > minSize) {
+ topRightRadius = minSize;
+ }
+ if (bottomLeftRadius > minSize) {
+ bottomLeftRadius = minSize;
+ }
+ if (bottomRightRadius > minSize) {
+ bottomRightRadius = minSize;
+ }
+
+ path.moveTo(left + topLeftRadius, top);
+ path.lineTo(right - topRightRadius, top);
+
+ //float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean forceMoveTo
+ if (useBezier) {
+ path.quadTo(right, top, right, top + topRightRadius);
+ } else {
+ path.arcTo(new RectF(right - topRightRadius * 2f, top, right, top + topRightRadius * 2f), -90, 90);
+ }
+ path.lineTo(right, bottom - bottomRightRadius);
+ if (useBezier) {
+ path.quadTo(right, bottom, right - bottomRightRadius, bottom);
+ } else {
+ path.arcTo(new RectF(right - bottomRightRadius * 2f, bottom - bottomRightRadius * 2f, right, bottom), 0, 90);
+ }
+ path.lineTo(left + bottomLeftRadius, bottom);
+ if (useBezier) {
+ path.quadTo(left, bottom, left, bottom - bottomLeftRadius);
+ } else {
+ path.arcTo(new RectF(left, bottom - bottomLeftRadius * 2f, left + bottomLeftRadius * 2f, bottom), 90, 90);
+ }
+ path.lineTo(left, top + topLeftRadius);
+ if (useBezier) {
+ path.quadTo(left, top, left + topLeftRadius, top);
+ } else {
+ path.arcTo(new RectF(left, top, left + topLeftRadius * 2f, top + topLeftRadius * 2f), 180, 90);
+ }
+ path.close();
+
+ return path;
+ }
+
+ public void setDrawable(Drawable drawable) {
+ this.drawable = drawable;
+ requiresShapeUpdate();
+ }
+
+ public void setDrawable(int redId) {
+ setDrawable(AppCompatResources.getDrawable(imageView.getContext(), redId));
+ }
+
+ public void requiresShapeUpdate() {
+ borderPath.set(generatePath(borderRectF,
+ topLeftRadius,
+ topRightRadius,
+ bottomRightRadius,
+ bottomLeftRadius
+ ));
+ requiersShapeUpdate = true;
+ imageView.postInvalidate();
+ }
+
+ public void dispatchOnDraw(Canvas canvas) {
+ if (requiersShapeUpdate) {
+ calculateLayout(canvas.getWidth(), canvas.getHeight());
+ requiersShapeUpdate = false;
+ }
+
+ if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1){
+ canvas.drawPath(clipPath, clipPaint);
+ } else {
+ canvas.drawPath(rectView, clipPaint);
+ }
+
+ if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) {
+ imageView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ }
+ }
+
+ private void calculateLayout(int width, int height) {
+ rectView.reset();
+ rectView.addRect(0f, 0f, 1f * imageView.getWidth(), 1f * imageView.getHeight(), Path.Direction.CW);
+
+ if (clipManager != null) {
+ if (width > 0 && height > 0) {
+ clipManager.setupClipLayout(width, height);
+ clipPath.reset();
+ clipPath.set(clipManager.createMask(width, height));
+
+ //invert the path for android P
+ if(Build.VERSION.SDK_INT > Build.VERSION_CODES.O_MR1) {
+ final boolean success = rectView.op(clipPath, Path.Op.DIFFERENCE);
+ }
+
+ //this needs to be fixed for 25.4.0
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && ViewCompat.getElevation(imageView) > 0f) {
+ try {
+ imageView.setOutlineProvider(getOutlineProvider());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ imageView.postInvalidate();
+ }
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ public ViewOutlineProvider getOutlineProvider() {
+ return new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ final Path shadowConvexPath = clipManager.getShadowConvexPath();
+ if (shadowConvexPath != null) {
+ try {
+ outline.setConvexPath(shadowConvexPath);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ }
+ };
+
+ }
+
+
+
+
+
+
+
+
+
+// private static final float DEFAULT_RADIUS = 0f;
+//
+// private final float[] cornerRadius = new float[] {
+// DEFAULT_RADIUS,
+// DEFAULT_RADIUS,
+// DEFAULT_RADIUS,
+// DEFAULT_RADIUS
+// };
+// private Drawable backgroundDrawable; //? needed? @Nullable ? @NonNull?
+// private Drawable drawable; //? needed? @Nullable ? @NonNull?private boolean mMutateBackground = false;
+
+
+
+ /**
+ * @return the largest corner radius.
+ */
+// public float getCornerRadiuses() {
+// return getMaxCornerRadius();
+// }
+
+ /**
+ * @return the largest corner radius.
+ */
+// public float getMaxCornerRadius() {
+// float maxRadius = DEFAULT_RADIUS;
+// for (int i = cornerRadius.length - 1; i >= 0; i--) {
+// maxRadius = Math.max(cornerRadius[i], maxRadius);
+// }
+// return maxRadius;
+// }
+
+ /**
+ * Get the imageCorner radius of a specified imageCorner.
+ *
+ * @param imageCorner the imageCorner.
+ * @return the radius.
+ */
+// public float getCornerRadius(@Corner int imageCorner) {
+// return cornerRadius[imageCorner];
+// }
+
+ /**
+ * Set the corner radii of all corners in px.
+ *
+ * @param radius the radius to set.
+ */
+// public void setCornerRadiuses(int radius) {
+// setCornerRadius(radius, radius, radius, radius);
+// }
+
+ /**
+ * Set all the corner radii from a dimension resource id.
+ *
+ * @param resId dimension resource id of radii.
+ */
+// public void setCornerRadiusDimen(@DimenRes int resId) {
+// float radius = imageView.getResources().getDimension(resId);
+// setCornerRadius(radius, radius, radius, radius);
+// }
+
+ /**
+ * Set the corner radius of a specific corner from a dimension resource id.
+ *
+ * @param corner the corner to set.
+ * @param resId the dimension resource id of the corner radius.
+ */
+// public void setCornerRadiusDimen(@Corner int corner, @DimenRes int resId) {
+// if (corner == Corner.NONE) {
+// return;
+// }
+// setCornerRadius(corner, imageView.getResources().getDimensionPixelSize(resId));
+// }
+
+ /**
+ * Set the corner radii of all corners in px.
+ *
+ * @param radius the radius to set.
+ */
+// public void setCornerRadius(float radius) {
+// setCornerRadius(radius, radius, radius, radius);
+// }
+
+ /**
+ * Set the corner radius of a specific corner in px.
+ *
+ * @param corner the corner to set.
+ * @param radius the corner radius to set in px.
+ */
+// public void setCornerRadius(@Corner int corner, float radius) {
+// if (cornerRadius[corner] == radius) {
+// return;
+// }
+//
+// cornerRadius[corner] = radius;
+//
+// updateDrawableAttrs();
+// updateBackgroundDrawableAttrs(false);
+// imageView.invalidate();
+// }
+
+ /**
+ * Set the corner radii of each corner individually. Currently only one unique nonzero value is
+ * supported.
+ *
+// * @param topLeft radius of the top left corner in px.
+// * @param topRight radius of the top right corner in px.
+// * @param bottomRight radius of the bottom right corner in px.
+// * @param bottomLeft radius of the bottom left corner in px.
+ */
+// public void setCornerRadius(float topLeft, float topRight, float bottomLeft, float bottomRight) {
+// if (cornerRadius[Corner.TOP_LEFT] == topLeft && cornerRadius[Corner.TOP_RIGHT] == topRight && cornerRadius[Corner.BOTTOM_RIGHT] == bottomRight && cornerRadius[Corner.BOTTOM_LEFT] == bottomLeft) {
+// return;
+// }
+//
+// cornerRadius[Corner.TOP_LEFT] = topLeft;
+// cornerRadius[Corner.TOP_RIGHT] = topRight;
+// cornerRadius[Corner.BOTTOM_LEFT] = bottomLeft;
+// cornerRadius[Corner.BOTTOM_RIGHT] = bottomRight;
+//
+// updateDrawableAttrs();
+// updateBackgroundDrawableAttrs(false);
+// imageView.invalidate();
+// }
+
+
+
+
+
+
+
+ @Override
+ public Drawable modifiedDrawable(Drawable drawable) {
+// this.drawable = SuperDrawable.fromDrawable(drawable);
+ updateDrawableAttrs();
+ return this.drawable;
+ }
+
+ @Override
+ public Drawable modifiedDrawable(Bitmap bitmap) {
+// this.drawable = SuperDrawable.fromBitmap(bitmap);
+ updateDrawableAttrs();
+ return this.drawable;
+ }
+
+ @Override
+ public void notifyDrawableStateChanges() {
+// imageView.invalidate();
+ }
+
+// @Override
+// public void delegateScaleType(ImageView.ScaleType scaleType) {
+// // TODO: 8/28/18 CHECK IF REALLY NEEDED
+// if (imageView.getScaleType() != scaleType) {
+// updateDrawableAttrs();
+// updateBackgroundDrawableAttrs(false);
+// }
+// // parent scaleType invalidates.
+// }
+
+ private void updateDrawableAttrs() {
+ updateAttrs(drawable);
+ }
+
+ private void updateAttrs(Drawable drawable) {
+ if (drawable == null) { return; }
+
+ // TODO how this can be possible?
+// if (drawable instanceof SuperDrawable) {
+// ((SuperDrawable) drawable).setCornerRadius(
+// cornerRadius[Corner.TOP_LEFT],
+// cornerRadius[Corner.TOP_RIGHT],
+// cornerRadius[Corner.BOTTOM_LEFT],
+// cornerRadius[Corner.BOTTOM_RIGHT]
+// );
+// }
+ }
+
+
+
+// private void updateBackgroundDrawableAttrs(boolean convert) {
+// if (mutateBackground) {
+// if (convert) {
+//// backgroundDrawable = SuperDrawable.fromDrawable(backgroundDrawable);
+// }
+// updateAttrs(backgroundDrawable);
+// }
+// }
+
+
+
+
+
+
+
+
+
+// @Override
+// public Drawable delegateSetImageBitmap(Bitmap bm) {
+// drawable = SuperDrawable.fromBitmap(bm);
+// updateDrawableAttrs();
+// imageView.setImageDrawable(this.drawable);
+// return drawable;
+// }
+
+
+
+
+
+
+
+
+// @Override
+// public void setImageBitmap(Bitmap bm) {
+//
+//
+// super.setImageDrawable(drawable);
+// }
+//
+// @Override
+// public void setImageResource(@DrawableRes int resId) {
+// if (resource != resId) {
+// resource = resId;
+// drawable = resolveResource();
+// updateDrawableAttrs();
+// super.setImageDrawable(drawable);
+// }
+// }
+//
+// @Override
+// public void setImageURI(Uri uri) {
+// super.setImageURI(uri);
+// setImageDrawable(getDrawable());
+// }
+//
+// private Drawable resolveResource() {
+// Resources rsrc = getResources();
+// if (rsrc == null) { return null; }
+//
+// Drawable d = null;
+//
+// if (resource != 0) {
+// try {
+// d = rsrc.getDrawable(resource);
+// } catch (Exception e) {
+// Log.w(TAG, "Unable to find resource: " + resource, e);
+// // Don't try again.
+// resource = 0;
+// }
+// }
+// return SuperDrawable.fromDrawable(d);
+// }
+//
+// @Override
+// public void setBackground(Drawable background) {
+// setBackgroundDrawable(background);
+// }
+//
+// @Override
+// public void setBackgroundResource(@DrawableRes int resId) {
+// if (backgroundResource != resId) {
+// backgroundResource = resId;
+// backgroundDrawable = resolveBackgroundResource();
+// setBackgroundDrawable(backgroundDrawable);
+// }
+// }
+//
+// @Override
+// public void setBackgroundColor(int color) {
+// backgroundDrawable = new ColorDrawable(color);
+// setBackgroundDrawable(backgroundDrawable);
+// }
+//
+// private Drawable resolveBackgroundResource() {
+// Resources rsrc = getResources();
+// if (rsrc == null) { return null; }
+//
+// Drawable d = null;
+//
+// if (backgroundResource != 0) {
+// try {
+// d = rsrc.getDrawable(backgroundResource);
+// } catch (Exception e) {
+// Log.w(TAG, "Unable to find resource: " + backgroundResource, e);
+// // Don't try again.
+// backgroundResource = 0;
+// }
+// }
+// return SuperDrawable.fromDrawable(d);
+// }
+//
+// @Override
+// @Deprecated
+// public void setBackgroundDrawable(Drawable background) {
+// backgroundDrawable = background;
+// updateBackgroundDrawableAttrs(true);
+// //noinspection deprecation
+// super.setBackgroundDrawable(backgroundDrawable);
+// }
+
+
+
+// /**
+// * If {@code true}, we will also round the background drawable according to the settings on this
+// * ImageView.
+// *
+// * @return whether the background is mutated.
+// */
+// public boolean mutatesBackground() {
+// return mMutateBackground;
+// }
+//
+// /**
+// * Set whether the {@link RoundedImageView} should round the background drawable according to
+// * the settings in addition to the source drawable.
+// *
+// * @param mutate true if this view should mutate the background drawable.
+// */
+// public void mutateBackground(boolean mutate) {
+// if (mMutateBackground == mutate) { return; }
+//
+// mMutateBackground = mutate;
+// updateBackgroundDrawableAttrs(true);
+// invalidate();
+// }
+}
diff --git a/cropimageview/src/main/java/com/cesards/cropimageview/RoundedCornerImageViewHook.java b/cropimageview/src/main/java/com/cesards/cropimageview/RoundedCornerImageViewHook.java
new file mode 100644
index 0000000..4376655
--- /dev/null
+++ b/cropimageview/src/main/java/com/cesards/cropimageview/RoundedCornerImageViewHook.java
@@ -0,0 +1,60 @@
+package com.cesards.cropimageview;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+public interface RoundedCornerImageViewHook {
+ void setup(@NonNull Context context, @Nullable AttributeSet attributeSet);
+
+ // void delegateDispatchDraw(Canvas canvas);
+
+
+
+
+
+
+
+ /**
+ * Needed for {@link ImageView#setImageDrawable(Drawable)}
+ * We process the drawable that will be set in the ImageView and we use it as a hook for every
+ * time {@link ImageView#setImageDrawable(Drawable)} is called
+ *
+ * This should be passed to the parent by the ImageView:
+ * super.setImageDrawable(roundedImage.modifiedDrawable(drawable));
+ *
+ *
+ *
+ *
+ */
+ Drawable modifiedDrawable(Drawable drawable);
+
+ /**
+ * Usage:
+ *
+ * @Override
+ * public void setImageBitmap(Bitmap bm) {
+ * super.setImageDrawable(roundedImage.modifiedDrawable(bm));
+ * }
+ */
+ Drawable modifiedDrawable(Bitmap bitmap);
+
+ /**
+ * Needed for {@link ImageView#drawableStateChanged()}
+ *
+ * Usage:
+ *
+ * @Override
+ * protected void drawableStateChanged() {
+ * super.drawableStateChanged();
+ * roundedImage.notifyDrawableStateChanges();
+ * }
+ */
+ void notifyDrawableStateChanges();
+}
diff --git a/cropimageview/src/main/java/com/cesards/cropimageview/model/CropType.java b/cropimageview/src/main/java/com/cesards/cropimageview/crop/CropType.java
similarity index 94%
rename from cropimageview/src/main/java/com/cesards/cropimageview/model/CropType.java
rename to cropimageview/src/main/java/com/cesards/cropimageview/crop/CropType.java
index e405011..aa0c4c4 100644
--- a/cropimageview/src/main/java/com/cesards/cropimageview/model/CropType.java
+++ b/cropimageview/src/main/java/com/cesards/cropimageview/crop/CropType.java
@@ -1,4 +1,4 @@
-package com.cesards.cropimageview.model;
+package com.cesards.cropimageview.crop;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -8,6 +8,7 @@
/**
* Options for cropping the bounds of an image to the bounds of the ImageView.
*/
+@Retention(RetentionPolicy.SOURCE)
@IntDef({
CropType.NONE,
CropType.LEFT_TOP,
@@ -19,7 +20,6 @@
CropType.CENTER_TOP,
CropType.CENTER_BOTTOM,
})
-@Retention(RetentionPolicy.SOURCE)
public @interface CropType {
int NONE = -1;
diff --git a/cropimageview/src/main/java/com/cesards/cropimageview/crop/ImageTransformation.java b/cropimageview/src/main/java/com/cesards/cropimageview/crop/ImageTransformation.java
new file mode 100644
index 0000000..e747c2d
--- /dev/null
+++ b/cropimageview/src/main/java/com/cesards/cropimageview/crop/ImageTransformation.java
@@ -0,0 +1,140 @@
+package com.cesards.cropimageview.crop;
+
+import android.graphics.Matrix;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.widget.ImageView;
+
+import androidx.annotation.Nullable;
+
+public class ImageTransformation {
+
+ private final ImageView imageView;
+ private final CompatMatrix compatMatrix;
+
+ public ImageTransformation(ImageView imageView) {
+ this.imageView = imageView;
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ compatMatrix = new PreAPI18Matrix(imageView);
+ } else {
+ compatMatrix = new API18Matrix(imageView);
+ }
+ }
+
+ public void compute(@CropType int cropType) {
+ int viewWidth = imageView.getWidth() - imageView.getPaddingLeft() - imageView.getPaddingRight();
+ int viewHeight = imageView.getHeight() - imageView.getPaddingTop() - imageView.getPaddingBottom();
+
+ if (cropType != CropType.NONE && viewHeight > 0 && viewWidth > 0) {
+ Matrix matrix = compatMatrix.matrix(cropType);
+
+ Drawable drawable = imageView.getDrawable();
+ int drawableWidth = drawable.getIntrinsicWidth();
+ int drawableHeight = drawable.getIntrinsicHeight();
+
+ float scaleY = (float) viewHeight / (float) drawableHeight;
+ float scaleX = (float) viewWidth / (float) drawableWidth;
+ float scale = scaleX > scaleY ? scaleX : scaleY;
+ matrix.setScale(scale, scale); // Same as doing matrix.reset() and matrix.preScale(...)
+
+ boolean verticalImageMode = scaleX > scaleY;
+
+ float postDrawableWidth = drawableWidth * scale;
+ float xTranslation = getXTranslation(cropType, viewWidth, postDrawableWidth, verticalImageMode);
+ float postDrawabeHeigth = drawableHeight * scale;
+ float yTranslation = getYTranslation(cropType, viewHeight, postDrawabeHeigth, verticalImageMode);
+
+ matrix.postTranslate(xTranslation, yTranslation);
+ imageView.setImageMatrix(matrix);
+ }
+ }
+
+ private float getYTranslation(
+ @CropType int cropType,
+ int viewHeight,
+ float postDrawableHeight,
+ boolean verticalImageMode
+ ) {
+ if (verticalImageMode) {
+ switch (cropType) {
+ case CropType.CENTER_BOTTOM:
+ case CropType.LEFT_BOTTOM:
+ case CropType.RIGHT_BOTTOM:
+ return viewHeight - postDrawableHeight;
+ case CropType.LEFT_CENTER:
+ case CropType.RIGHT_CENTER:
+ // View in the middle of the screen
+ return (viewHeight - postDrawableHeight) / 2f;
+ }
+ }
+
+ // All other cases we don't need to translate
+ return 0f;
+ }
+
+ private float getXTranslation(
+ @CropType int cropType,
+ int viewWidth,
+ float postDrawableWidth,
+ boolean verticalImageMode
+ ) {
+ if (!verticalImageMode) {
+ switch (cropType) {
+ case CropType.RIGHT_TOP:
+ case CropType.RIGHT_CENTER:
+ case CropType.RIGHT_BOTTOM:
+ return viewWidth - postDrawableWidth;
+ case CropType.CENTER_TOP:
+ case CropType.CENTER_BOTTOM:
+ // View in the middle of the screen
+ return (viewWidth - postDrawableWidth) / 2f;
+ }
+ }
+ // All other cases we don't need to translate
+ return 0f;
+ }
+
+
+ private static final class PreAPI18Matrix extends CompatMatrix {
+
+ @Nullable
+ private Matrix matrix;
+
+ PreAPI18Matrix(ImageView imageView) {
+ super(imageView);
+ }
+
+ @Override
+ Matrix matrix(int cropType) {
+ if (cropType != CropType.NONE && matrix == null) {
+ matrix = new Matrix();
+ }
+
+ return matrix != null ? matrix : imageView.getImageMatrix();
+ }
+ }
+
+ private static final class API18Matrix extends CompatMatrix {
+
+ API18Matrix(ImageView imageView) {
+ super(imageView);
+ }
+
+ @Override
+ Matrix matrix(int cropType) {
+ return imageView.getImageMatrix();
+ }
+ }
+
+ static abstract class CompatMatrix {
+
+ final ImageView imageView;
+
+ CompatMatrix(ImageView imageView) {
+ this.imageView = imageView;
+ }
+
+ abstract Matrix matrix(@CropType int cropType);
+ }
+}
diff --git a/cropimageview/src/main/java/com/cesards/cropimageview/delegation/Crop.java b/cropimageview/src/main/java/com/cesards/cropimageview/delegation/Crop.java
deleted file mode 100644
index b4a1bd2..0000000
--- a/cropimageview/src/main/java/com/cesards/cropimageview/delegation/Crop.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.cesards.cropimageview.delegation;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-public interface Crop {
- void initialize(@NonNull Context context, @Nullable AttributeSet attributeSet);
- boolean delegateSetFrame(boolean setFrameResult);
- void delegateSetImageBitmap(Bitmap bitmap);
- void delegateSetImageDrawable(Drawable drawable);
- void delegateSetImageResource(int resId);
-}
diff --git a/cropimageview/src/main/java/com/cesards/cropimageview/delegation/CropDelegation.java b/cropimageview/src/main/java/com/cesards/cropimageview/delegation/CropDelegation.java
deleted file mode 100644
index d65be99..0000000
--- a/cropimageview/src/main/java/com/cesards/cropimageview/delegation/CropDelegation.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package com.cesards.cropimageview.delegation;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.widget.ImageView;
-
-import com.cesards.cropimageview.R;
-import com.cesards.cropimageview.model.CropImage;
-import com.cesards.cropimageview.model.CropImageFactory;
-import com.cesards.cropimageview.model.CropType;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-public final class CropDelegation implements Crop {
-
- @NonNull private final ImageView imageView;
- @Nullable private CropImage cropImage;
- private int cropType = CropType.NONE;
-
- public CropDelegation(@NonNull ImageView imageView) {
- this.imageView = imageView;
- }
-
- /**
- * Set crop type for the {@link ImageView}
- *
- * @param cropType A {@link CropType} desired scaling mode.
- */
- public void setCropType(@CropType int cropType) {
- this.cropType = cropType;
-
- imageView.setWillNotCacheDrawing(false);
-
- imageView.requestLayout();
- imageView.invalidate();
- }
-
- @Override
- public void initialize(@NonNull Context context, @Nullable AttributeSet attributeSet) {
- if (attributeSet != null) {
- parseAttributes(attributeSet);
- }
- setup();
- }
-
- /**
- * Return the current crop type in use by this ImageView.
- *
- * @return a {@link CropType} in use by this ImageView
- */
- @CropType
- public int getCropType() {
- return cropType;
- }
-
- @Override
- public boolean delegateSetFrame(boolean setFrameResult) {
- if (!imageView.isInEditMode() && cropImage != null && imageView.getDrawable() != null) {
- cropImage.computeImageTransformation();
- }
- return setFrameResult;
- }
-
- @Override
- public void delegateSetImageBitmap(Bitmap bitmap) {
- setup();
- }
-
- @Override
- public void delegateSetImageDrawable(Drawable drawable) {
- setup();
- }
-
- @Override
- public void delegateSetImageResource(int resId) {
- setup();
- }
-
- private void setup() {
- imageView.setScaleType(ImageView.ScaleType.MATRIX);
-
- if (imageView.getDrawable() != null) {
- cropImage = new CropImageFactory().getCropImage(imageView, cropType);
- }
- }
-
- private void parseAttributes(AttributeSet attrs) {
- final TypedArray a = imageView.getContext().obtainStyledAttributes(attrs, R.styleable.civ_CropImageView);
- cropType = a.getInt(R.styleable.civ_CropImageView_civ_crop, CropType.NONE);
- a.recycle();
- }
-}
diff --git a/cropimageview/src/main/java/com/cesards/cropimageview/model/API18Image.java b/cropimageview/src/main/java/com/cesards/cropimageview/model/API18Image.java
deleted file mode 100644
index aea6db8..0000000
--- a/cropimageview/src/main/java/com/cesards/cropimageview/model/API18Image.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.cesards.cropimageview.model;
-
-import android.graphics.Matrix;
-import android.widget.ImageView;
-
-import com.cesards.cropimageview.CropImageView;
-
-public class API18Image extends CropImage {
-
- API18Image(ImageView imageView, @CropType int cropType) {
- super(imageView, cropType);
- }
-
- @Override
- public Matrix getMatrix() {
- return imageView.getImageMatrix();
- }
-}
\ No newline at end of file
diff --git a/cropimageview/src/main/java/com/cesards/cropimageview/model/CropImage.java b/cropimageview/src/main/java/com/cesards/cropimageview/model/CropImage.java
deleted file mode 100644
index 6945cdc..0000000
--- a/cropimageview/src/main/java/com/cesards/cropimageview/model/CropImage.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package com.cesards.cropimageview.model;
-
-import android.graphics.Matrix;
-import android.graphics.drawable.Drawable;
-import android.widget.ImageView;
-
-import androidx.annotation.NonNull;
-
-public abstract class CropImage implements Transformation {
-
- @NonNull final ImageView imageView;
- @CropType private final int cropType;
-
- public CropImage(@NonNull ImageView imageView, @CropType int cropType) {
- this.imageView = imageView;
- this.cropType = cropType;
- }
-
- public void computeImageTransformation() {
- int viewWidth = imageView.getWidth() - imageView.getPaddingLeft() - imageView.getPaddingRight();
- int viewHeight = imageView.getHeight() - imageView.getPaddingTop() - imageView.getPaddingBottom();
-
- if (cropType != CropType.NONE && viewHeight > 0 && viewWidth > 0) {
- Matrix matrix = getMatrix();
-
- Drawable drawable = imageView.getDrawable();
- int drawableWidth = drawable.getIntrinsicWidth();
- int drawableHeight = drawable.getIntrinsicHeight();
-
- float scaleY = (float) viewHeight / (float) drawableHeight;
- float scaleX = (float) viewWidth / (float) drawableWidth;
- float scale = scaleX > scaleY ? scaleX : scaleY;
- matrix.setScale(scale, scale); // Same as doing matrix.reset() and matrix.preScale(...)
-
- boolean verticalImageMode = scaleX > scaleY;
-
- float postDrawableWidth = drawableWidth * scale;
- float xTranslation = getXTranslation(cropType, viewWidth, postDrawableWidth, verticalImageMode);
- float postDrawabeHeigth = drawableHeight * scale;
- float yTranslation = getYTranslation(cropType, viewHeight, postDrawabeHeigth, verticalImageMode);
-
- matrix.postTranslate(xTranslation, yTranslation);
- imageView.setImageMatrix(matrix);
- }
- }
-
- private float getYTranslation(@CropType int cropType,
- int viewHeight,
- float postDrawabeHeigth,
- boolean verticalImageMode) {
- if (verticalImageMode) {
- switch (cropType) {
- case CropType.CENTER_BOTTOM:
- case CropType.LEFT_BOTTOM:
- case CropType.RIGHT_BOTTOM:
- return viewHeight - postDrawabeHeigth;
- case CropType.LEFT_CENTER:
- case CropType.RIGHT_CENTER:
- // View in the middle of the screen
- return (viewHeight - postDrawabeHeigth) / 2f;
- }
- }
-
- // All other cases we don't need to translate
- return 0f;
- }
-
- private float getXTranslation(@CropType int cropType,
- int viewWidth,
- float postDrawableWidth,
- boolean verticalImageMode) {
- if (!verticalImageMode) {
- switch (cropType) {
- case CropType.RIGHT_TOP:
- case CropType.RIGHT_CENTER:
- case CropType.RIGHT_BOTTOM:
- return viewWidth - postDrawableWidth;
- case CropType.CENTER_TOP:
- case CropType.CENTER_BOTTOM:
- // View in the middle of the screen
- return (viewWidth - postDrawableWidth) / 2f;
- }
- }
- // All other cases we don't need to translate
- return 0f;
- }
-}
diff --git a/cropimageview/src/main/java/com/cesards/cropimageview/model/CropImageFactory.java b/cropimageview/src/main/java/com/cesards/cropimageview/model/CropImageFactory.java
deleted file mode 100644
index ad98a0d..0000000
--- a/cropimageview/src/main/java/com/cesards/cropimageview/model/CropImageFactory.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.cesards.cropimageview.model;
-
-import android.os.Build;
-import android.widget.ImageView;
-
-import com.cesards.cropimageview.CropImageView;
-
-import androidx.annotation.NonNull;
-
-public class CropImageFactory {
-
- public CropImage getCropImage(@NonNull ImageView imageView, @CropType int cropType) {
- final boolean preApi18 = Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2;
- return preApi18 ? new PreApi18CropImage(imageView, cropType) : new API18Image(imageView, cropType);
- }
-}
diff --git a/cropimageview/src/main/java/com/cesards/cropimageview/model/PreApi18CropImage.java b/cropimageview/src/main/java/com/cesards/cropimageview/model/PreApi18CropImage.java
deleted file mode 100644
index 43cf04c..0000000
--- a/cropimageview/src/main/java/com/cesards/cropimageview/model/PreApi18CropImage.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.cesards.cropimageview.model;
-
-import android.graphics.Matrix;
-import android.widget.ImageView;
-
-import com.cesards.cropimageview.CropImageView;
-
-public final class PreApi18CropImage extends CropImage {
-
- private Matrix matrix;
-
- PreApi18CropImage(final ImageView imageView, final @CropType int cropType) {
- super(imageView, cropType);
- init(cropType);
- }
-
- private void init(@CropType int cropType) {
- if (cropType != CropType.NONE) {
- matrix = new Matrix();
- }
- }
-
- @Override
- public Matrix getMatrix() {
- return matrix == null ? imageView.getImageMatrix() : matrix;
- }
-}
diff --git a/cropimageview/src/main/java/com/cesards/cropimageview/model/Transformation.java b/cropimageview/src/main/java/com/cesards/cropimageview/model/Transformation.java
deleted file mode 100644
index 717ae5c..0000000
--- a/cropimageview/src/main/java/com/cesards/cropimageview/model/Transformation.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.cesards.cropimageview.model;
-
-import android.graphics.Matrix;
-
-public interface Transformation {
- Matrix getMatrix();
-}
diff --git a/cropimageview/src/main/java/com/cesards/cropimageview/rounded_corners/ClipPathManager.java b/cropimageview/src/main/java/com/cesards/cropimageview/rounded_corners/ClipPathManager.java
new file mode 100644
index 0000000..20c0e69
--- /dev/null
+++ b/cropimageview/src/main/java/com/cesards/cropimageview/rounded_corners/ClipPathManager.java
@@ -0,0 +1,64 @@
+package com.cesards.cropimageview.rounded_corners;
+
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+
+import androidx.annotation.Nullable;
+
+public final class ClipPathManager {
+
+ protected final Path path = new Path();
+ private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+ private ClipPathCreator createClipPath = null;
+
+ public ClipPathManager() {
+ paint.setColor(Color.BLACK);
+ paint.setStyle(Paint.Style.FILL);
+ paint.setAntiAlias(true);
+ paint.setStrokeWidth(1);
+ }
+
+ public Paint getPaint() {
+ return paint;
+ }
+
+ public boolean requiresBitmap() {
+ return createClipPath != null && createClipPath.requiresBitmap();
+ }
+
+ @Nullable
+ public final Path createClipPath(int width, int height) {
+ if (createClipPath != null) {
+ return createClipPath.createClipPath(width, height);
+ }
+ return null;
+ }
+
+ public void setClipPathCreator(ClipPathCreator createClipPath) {
+ this.createClipPath = createClipPath;
+ }
+
+ public Path createMask(int width, int height) {
+ return path;
+ }
+
+ @Nullable
+ public Path getShadowConvexPath() {
+ return path;
+ }
+
+ public void setupClipLayout(int width, int height) {
+ path.reset();
+ final Path clipPath = createClipPath(width, height);
+ if (clipPath != null) {
+ path.set(clipPath);
+ }
+ }
+
+ public interface ClipPathCreator {
+ Path createClipPath(int width, int height);
+ boolean requiresBitmap();
+ }
+}
diff --git a/cropimageview/src/main/java/com/cesards/cropimageview/rounded_corners/Corner.java b/cropimageview/src/main/java/com/cesards/cropimageview/rounded_corners/Corner.java
new file mode 100644
index 0000000..b8986fc
--- /dev/null
+++ b/cropimageview/src/main/java/com/cesards/cropimageview/rounded_corners/Corner.java
@@ -0,0 +1,31 @@
+package com.cesards.cropimageview.rounded_corners;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import androidx.annotation.IntDef;
+
+import static com.cesards.cropimageview.rounded_corners.Corner.BOTTOM_LEFT;
+import static com.cesards.cropimageview.rounded_corners.Corner.BOTTOM_RIGHT;
+import static com.cesards.cropimageview.rounded_corners.Corner.NONE;
+import static com.cesards.cropimageview.rounded_corners.Corner.TOP_LEFT;
+import static com.cesards.cropimageview.rounded_corners.Corner.TOP_RIGHT;
+
+/**
+ * Options for cropping the bounds of an image to the bounds of the ImageView.
+ */
+@Retention(RetentionPolicy.SOURCE)
+@IntDef({
+ NONE,
+ TOP_LEFT,
+ TOP_RIGHT,
+ BOTTOM_LEFT,
+ BOTTOM_RIGHT,
+})
+public @interface Corner {
+ int NONE = -1;
+ int TOP_LEFT = 0;
+ int TOP_RIGHT = 1;
+ int BOTTOM_LEFT = 2;
+ int BOTTOM_RIGHT = 3;
+}
\ No newline at end of file
diff --git a/cropimageview/src/main/java/com/cesards/cropimageview/rounded_corners/RoundedBitmapViewDrawable.java b/cropimageview/src/main/java/com/cesards/cropimageview/rounded_corners/RoundedBitmapViewDrawable.java
new file mode 100644
index 0000000..77a85e6
--- /dev/null
+++ b/cropimageview/src/main/java/com/cesards/cropimageview/rounded_corners/RoundedBitmapViewDrawable.java
@@ -0,0 +1,494 @@
+package com.cesards.cropimageview.rounded_corners;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Shader;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * shows a bitmap as if it had rounded corners. based on :
+ * http://rahulswackyworld.blogspot.co.il/2013/04/android-drawables-with-rounded_7.html
+ * easy alternative from support library: RoundedBitmapDrawableFactory.create( ...) ;
+ */
+//public class RoundedBitmapViewDrawable extends RoundedBitmapDrawable {
+class RoundedBitmapViewDrawable extends Drawable {
+
+ @Override
+ public void draw(@NonNull Canvas canvas) {
+
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+
+ }
+
+ @Override
+ public void setColorFilter(@Nullable ColorFilter colorFilter) {
+
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+
+
+
+
+
+ //
+// private final BitmapShader bitmapShader;
+// private final Paint p;
+// private final RectF rect;
+// private final float borderRadius;
+//
+// public RoundedBitmapViewDrawable(final Resources resources, final Bitmap bitmap, final float borderRadius) {
+// super(resources, bitmap);
+// bitmapShader = new BitmapShader(getBitmap(), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
+// final Bitmap b = getBitmap();
+// p = getPaint();
+// p.setAntiAlias(true);
+// p.setShader(bitmapShader);
+// final int w = b.getWidth(), h = b.getHeight();
+// rect = new RectF(0, 0, w, h);
+// this.borderRadius = borderRadius < 0 ? 0.15f * Math.min(w, h) : borderRadius;
+// }
+//
+// @Override
+// public void draw(final Canvas canvas) {
+// canvas.drawRoundRect(rect, borderRadius, borderRadius, p);
+// }
+//
+
+
+
+
+// private static final float DEFAULT_RADIUS = 0f;
+//
+// private final RectF bounds = new RectF();
+// private final RectF drawableRect = new RectF();
+// private final RectF bitmapRect = new RectF();
+// private final Bitmap bitmap;
+// private final Paint bitmapPaint;
+// private final int bitmapWidth;
+// private final int bitmapHeight;
+// private final Matrix shaderMatrix = new Matrix();
+// private final RectF squareCornersRect = new RectF();
+// private Shader.TileMode tileModeX = Shader.TileMode.CLAMP;
+// private Shader.TileMode tileModeY = Shader.TileMode.CLAMP;
+// private boolean mRebuildShader = true;
+// private float cornerRadius = 0f;
+// private final boolean[] cornerRadiusRounded = new boolean[] { true, true, true, true };
+// private ImageView.ScaleType scaleType = ImageView.ScaleType.FIT_CENTER;
+//
+// public RoundedBitmapViewDrawable(Bitmap bitmap) {
+// this.bitmap = bitmap;
+//
+// bitmapWidth = bitmap.getWidth();
+// bitmapHeight = bitmap.getHeight();
+// bitmapRect.set(0, 0, bitmapWidth, bitmapHeight);
+//
+// bitmapPaint = new Paint();
+// bitmapPaint.setStyle(Paint.Style.FILL);
+// bitmapPaint.setAntiAlias(true);
+// }
+//
+// public static Drawable fromDrawable(Drawable drawable) {
+// if (drawable != null) {
+// if (drawable instanceof RoundedBitmapViewDrawable) {
+// // just return if it's already a RoundedBitmapViewDrawable
+// return drawable;
+// }
+//
+// // try to get a bitmap from the drawable and
+// Bitmap bm = drawableToBitmap(drawable);
+// if (bm != null) {
+// return new RoundedBitmapViewDrawable(bm);
+// }
+// }
+// return drawable;
+// }
+//
+// public static RoundedBitmapViewDrawable fromBitmap(Bitmap bitmap) {
+// if (bitmap != null) {
+// return new RoundedBitmapViewDrawable(bitmap);
+// } else {
+// return null;
+// }
+// }
+//
+// public static Bitmap drawableToBitmap(Drawable drawable) {
+// if (drawable instanceof BitmapDrawable) {
+// return ((BitmapDrawable) drawable).getBitmap();
+// }
+//
+// Bitmap bitmap;
+// int width = Math.max(drawable.getIntrinsicWidth(), 2);
+// int height = Math.max(drawable.getIntrinsicHeight(), 2);
+// try {
+// bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+// Canvas canvas = new Canvas(bitmap);
+// drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+// drawable.draw(canvas);
+// } catch (Exception e) {
+// e.printStackTrace();
+// Log.w(RoundedBitmapViewDrawable.class.getSimpleName(), "Failed to create bitmap from drawable!");
+// bitmap = null;
+// }
+//
+// return bitmap;
+// }
+//
+//
+//
+// public Bitmap getSourceBitmap() {
+// return bitmap;
+// }
+//
+// /**
+// * @return the corner radius.
+// */
+// public float getCornerRadius() {
+// return cornerRadius;
+// }
+//
+// /**
+// * @param corner the specific corner to get radius of.
+// * @return the corner radius of the specified corner.
+// */
+// public float getCornerRadius(@Corner int corner) {
+// return cornerRadiusRounded[corner] ? cornerRadius : 0f;
+// }
+//
+// /**
+// * Sets all corners to the specified radius.
+// *
+// * @param radius the radius.
+// * @return the {@link RoundedBitmapViewDrawable} for chaining.
+// */
+// public RoundedBitmapViewDrawable setCornerRadius(float radius) {
+// setCornerRadius(radius, radius, radius, radius);
+// return this;
+// }
+//
+// /**
+// * Sets the corner radius of one specific corner.
+// *
+// * @param corner the corner.
+// * @param radius the radius.
+// * @return the {@link RoundedBitmapViewDrawable} for chaining.
+// */
+// public RoundedBitmapViewDrawable setCornerRadius(@Corner int corner, float radius) {
+// if (radius != 0 && cornerRadius != 0 && cornerRadius != radius) {
+// throw new IllegalArgumentException("Multiple nonzero corner radii not yet supported.");
+// }
+//
+// if (radius == 0) {
+// if (only(corner, cornerRadiusRounded)) {
+// cornerRadius = 0;
+// }
+// cornerRadiusRounded[corner] = false;
+// } else {
+// if (cornerRadius == 0) {
+// cornerRadius = radius;
+// }
+// cornerRadiusRounded[corner] = true;
+// }
+//
+// return this;
+// }
+//
+// /**
+// * Sets the corner radii of all the corners.
+// *
+// * @param topLeft top left corner radius.
+// * @param topRight top right corner radius
+// * @param bottomRight bototm right corner radius.
+// * @param bottomLeft bottom left corner radius.
+// * @return the {@link RoundedBitmapViewDrawable} for chaining.
+// */
+// public RoundedBitmapViewDrawable setCornerRadius(
+// float topLeft,
+// float topRight,
+// float bottomRight,
+// float bottomLeft
+// ) {
+// Set radiusSet = new HashSet<>(4);
+// radiusSet.add(topLeft);
+// radiusSet.add(topRight);
+// radiusSet.add(bottomRight);
+// radiusSet.add(bottomLeft);
+//
+// radiusSet.remove(0f);
+//
+// if (radiusSet.size() > 1) {
+// throw new IllegalArgumentException("Multiple nonzero corner radii not yet supported.");
+// }
+//
+// if (!radiusSet.isEmpty()) {
+// float radius = radiusSet.iterator().next();
+// if (Float.isInfinite(radius) || Float.isNaN(radius) || radius < 0) {
+// throw new IllegalArgumentException("Invalid radius value: " + radius);
+// }
+// cornerRadius = radius;
+// } else {
+// cornerRadius = 0f;
+// }
+//
+// cornerRadiusRounded[Corner.TOP_LEFT] = topLeft > 0;
+// cornerRadiusRounded[Corner.TOP_RIGHT] = topRight > 0;
+// cornerRadiusRounded[Corner.BOTTOM_RIGHT] = bottomRight > 0;
+// cornerRadiusRounded[Corner.BOTTOM_LEFT] = bottomLeft > 0;
+// return this;
+// }
+//
+// public ImageView.ScaleType getScaleType() {
+// return scaleType;
+// }
+//
+// public RoundedBitmapViewDrawable setScaleType(ImageView.ScaleType scaleType) {
+// if (scaleType == null) {
+// scaleType = ImageView.ScaleType.FIT_CENTER;
+// }
+// if (this.scaleType != scaleType) {
+// this.scaleType = scaleType;
+// updateShaderMatrix();
+// }
+// return this;
+// }
+//
+// public Shader.TileMode getTileModeX() {
+// return tileModeX;
+// }
+//
+// public RoundedBitmapViewDrawable setTileModeX(Shader.TileMode tileModeX) {
+// if (this.tileModeX != tileModeX) {
+// this.tileModeX = tileModeX;
+// mRebuildShader = true;
+// invalidateSelf();
+// }
+// return this;
+// }
+//
+// public Shader.TileMode getTileModeY() {
+// return tileModeY;
+// }
+//
+// public RoundedBitmapViewDrawable setTileModeY(Shader.TileMode tileModeY) {
+// if (this.tileModeY != tileModeY) {
+// this.tileModeY = tileModeY;
+// mRebuildShader = true;
+// invalidateSelf();
+// }
+// return this;
+// }
+//
+// public Bitmap toBitmap() {
+// return drawableToBitmap(this);
+// }
+//
+// @Override
+// protected void onBoundsChange(@NonNull Rect bounds) {
+// super.onBoundsChange(bounds);
+//
+// bounds.set(bounds);
+//
+// updateShaderMatrix();
+// }
+//
+// @Override
+// public void draw(@NonNull Canvas canvas) {
+//
+// }
+//
+// // @Override
+//// public void draw(@NonNull Canvas canvas) {
+////// bitmapPaint.setShader(mShader);
+////// canvas.drawRoundRect(drawableRect, cornerRadius, cornerRadius, bitmapPaint);
+//// if (mRebuildShader) {
+//// BitmapShader bitmapShader = new BitmapShader(bitmap, tileModeX, tileModeY);
+//// if (tileModeX == Shader.TileMode.CLAMP && tileModeY == Shader.TileMode.CLAMP) {
+//// bitmapShader.setLocalMatrix(shaderMatrix);
+//// }
+//// bitmapPaint.setShader(bitmapShader);
+//// mRebuildShader = false;
+//// }
+////
+//// if (any(cornerRadiusRounded)) {
+//// float radius = cornerRadius;
+//// canvas.drawRoundRect(drawableRect, radius, radius, bitmapPaint);
+//// redrawBitmapForSquareCorners(canvas);
+//// } else {
+//// canvas.drawRect(drawableRect, bitmapPaint);
+//// }
+//// }
+//
+// @Override
+// public int getAlpha() {
+// return bitmapPaint.getAlpha();
+// }
+//
+// @Override
+// public void setAlpha(int alpha) {
+// bitmapPaint.setAlpha(alpha);
+// invalidateSelf();
+// }
+//
+// @Override
+// public ColorFilter getColorFilter() {
+// return bitmapPaint.getColorFilter();
+// }
+//
+// @Override
+// public void setColorFilter(ColorFilter cf) {
+// bitmapPaint.setColorFilter(cf);
+// invalidateSelf();
+// }
+//
+// @Override
+// public void setDither(boolean dither) {
+// bitmapPaint.setDither(dither);
+// invalidateSelf();
+// }
+//
+// @Override
+// public void setFilterBitmap(boolean filter) {
+// bitmapPaint.setFilterBitmap(filter);
+// invalidateSelf();
+// }
+//
+// @Override
+// public int getIntrinsicWidth() {
+// return bitmapWidth;
+// }
+//
+// @Override
+// public int getIntrinsicHeight() {
+// return bitmapHeight;
+// }
+//
+// private void updateShaderMatrix() {
+// float scale;
+// float dx;
+// float dy;
+//
+// switch (scaleType) {
+// case CENTER:
+// shaderMatrix.reset();
+// shaderMatrix.setTranslate(( bitmapWidth * 0.5f + 0.5f), bitmapHeight * 0.5f + 0.5f);
+// break;
+//
+// case CENTER_CROP:
+// break;
+//
+// case CENTER_INSIDE:
+// shaderMatrix.reset();
+//
+// if (bitmapWidth <= bounds.width() && bitmapHeight <= bounds.height()) {
+// scale = 1.0f;
+// } else {
+// scale = Math.min(bounds.width() / (float) bitmapWidth, bounds.height() / (float) bitmapHeight);
+// }
+//
+// dx = (int) ((bounds.width() - bitmapWidth * scale) * 0.5f + 0.5f);
+// dy = (int) ((bounds.height() - bitmapHeight * scale) * 0.5f + 0.5f);
+//
+// shaderMatrix.setScale(scale, scale);
+// shaderMatrix.postTranslate(dx, dy);
+// break;
+//
+// default:
+// case FIT_CENTER:
+// shaderMatrix.setRectToRect(bitmapRect, bounds, Matrix.ScaleToFit.CENTER);
+// break;
+//
+// case FIT_END:
+// shaderMatrix.setRectToRect(bitmapRect, bounds, Matrix.ScaleToFit.END);
+// break;
+//
+// case FIT_START:
+// shaderMatrix.setRectToRect(bitmapRect, bounds, Matrix.ScaleToFit.START);
+// break;
+//
+// case FIT_XY:
+// shaderMatrix.reset();
+// break;
+// }
+//
+// mRebuildShader = true;
+// }
+//
+// private void redrawBitmapForSquareCorners(Canvas canvas) {
+// if (all(cornerRadiusRounded)) {
+// // no square corners
+// return;
+// }
+//
+// if (cornerRadius == 0) {
+// return; // no round corners
+// }
+//
+// float left = drawableRect.left;
+// float top = drawableRect.top;
+// float right = left + drawableRect.width();
+// float bottom = top + drawableRect.height();
+// float radius = cornerRadius;
+//
+// if (!cornerRadiusRounded[Corner.TOP_LEFT]) {
+// squareCornersRect.set(left, top, left + radius, top + radius);
+// canvas.drawRect(squareCornersRect, bitmapPaint );
+// }
+//
+// if (!cornerRadiusRounded[Corner.TOP_RIGHT]) {
+// squareCornersRect.set(right - radius, top, right, radius);
+// canvas.drawRect(squareCornersRect, bitmapPaint );
+// }
+//
+// if (!cornerRadiusRounded[Corner.BOTTOM_RIGHT]) {
+// squareCornersRect.set(right - radius, bottom - radius, right, bottom);
+// canvas.drawRect(squareCornersRect, bitmapPaint );
+// }
+//
+// if (!cornerRadiusRounded[Corner.BOTTOM_LEFT]) {
+// squareCornersRect.set(left, bottom - radius, left + radius, bottom);
+// canvas.drawRect(squareCornersRect, bitmapPaint );
+// }
+// }
+//
+// private static boolean only(int index, boolean[] booleans) {
+// for (int i = 0, len = booleans.length; i < len; i++) {
+// if (booleans[i] != (i == index)) {
+// return false;
+// }
+// }
+// return true;
+// }
+//
+// private static boolean any(boolean[] booleans) {
+// for (boolean b : booleans) {
+// if (b) { return true; }
+// }
+// return false;
+// }
+//
+// private static boolean all(boolean[] booleans) {
+// for (boolean b : booleans) {
+// if (b) { return false; }
+// }
+// return true;
+// }
+}
diff --git a/cropimageview/src/main/res/values/attrs.xml b/cropimageview/src/main/res/values/attrs.xml
index 4f4c816..000fbfd 100644
--- a/cropimageview/src/main/res/values/attrs.xml
+++ b/cropimageview/src/main/res/values/attrs.xml
@@ -11,5 +11,11 @@
+
+
+
+
+
+
\ No newline at end of file