Skip to content

Commit

Permalink
feat(android): add "imageTouchFeedback" to ImageView
Browse files Browse the repository at this point in the history
Fixes TIMOB-28447
  • Loading branch information
jquick-axway authored and ewanharris committed Aug 3, 2021
1 parent c6c4b14 commit b2e84bd
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 18 deletions.
Expand Up @@ -22,6 +22,8 @@
TiC.PROPERTY_DURATION,
TiC.PROPERTY_ENABLE_ZOOM_CONTROLS,
TiC.PROPERTY_IMAGE,
TiC.PROPERTY_IMAGE_TOUCH_FEEDBACK,
TiC.PROPERTY_IMAGE_TOUCH_FEEDBACK_COLOR,
TiC.PROPERTY_IMAGES,
TiC.PROPERTY_REPEAT_COUNT
})
Expand Down
Expand Up @@ -12,12 +12,16 @@
import org.appcelerator.titanium.proxy.TiViewProxy;
import org.appcelerator.titanium.util.TiUIHelper;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.RippleDrawable;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
Expand All @@ -30,6 +34,8 @@
import android.widget.ImageView.ScaleType;
import android.widget.ZoomControls;
import android.graphics.PorterDuff.Mode;
import com.google.android.material.color.MaterialColors;
import org.appcelerator.titanium.R;
import org.appcelerator.titanium.util.TiColorHelper;

public class TiImageView extends ViewGroup implements Handler.Callback, OnClickListener
Expand All @@ -46,6 +52,10 @@ public class TiImageView extends ViewGroup implements Handler.Callback, OnClickL
private boolean enableScale;
private boolean enableZoomControls;

private boolean isImageRippleEnabled;
private int imageRippleColor;
private int defaultRippleColor;

private GestureDetector gestureDetector;
private ImageView imageView;
private ZoomControls zoomControls;
Expand Down Expand Up @@ -84,6 +94,9 @@ public TiImageView(Context context)
baseMatrix = new Matrix();
changeMatrix = new Matrix();

this.defaultRippleColor = MaterialColors.getColor(context, R.attr.colorControlHighlight, Color.DKGRAY);
this.imageRippleColor = defaultRippleColor;

imageView = new ImageView(context);
addView(imageView);
setEnableScale(true);
Expand Down Expand Up @@ -171,26 +184,92 @@ public void setEnableZoomControls(boolean enableZoomControls)
updateScaleType();
}

public boolean isImageRippleEnabled()
{
return this.isImageRippleEnabled;
}

public void setIsImageRippleEnabled(boolean value)
{
// Do not continue if setting isn't changing.
if (this.isImageRippleEnabled == value) {
return;
}

// Add or remove RippleDrawable to the image.
this.isImageRippleEnabled = value;
Bitmap bitmap = getImageBitmap();
if (bitmap != null) {
setImageBitmap(bitmap);
}
}

public int getImageRippleColor()
{
return this.imageRippleColor;
}

public int getDefaultRippleColor()
{
return this.defaultRippleColor;
}

public void setImageRippleColor(int value)
{
// Do not continue if setting isn't changing.
if (this.imageRippleColor == value) {
return;
}

// Update image's RippleDrawable with given color.
this.imageRippleColor = value;
if (this.isImageRippleEnabled) {
Bitmap bitmap = getImageBitmap();
if (bitmap != null) {
setImageBitmap(bitmap);
}
}
}

public Drawable getImageDrawable()
{
return imageView.getDrawable();
}

public Bitmap getImageBitmap()
{
Drawable drawable = getImageDrawable();
if (drawable instanceof RippleDrawable) {
if (((RippleDrawable) drawable).getNumberOfLayers() > 0) {
drawable = ((RippleDrawable) drawable).getDrawable(0);
}
}
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
return null;
}

/**
* Sets a Bitmap as the content of imageView
* @param bitmap The bitmap to set. If it is null, it will clear the previous image.
*/
public void setImageBitmap(Bitmap bitmap)
{
// Remove image from view if given null.
if (bitmap == null) {

// Reset drawable to null.
// setImageBitmap() will create a drawable that will affect width/height.
imageView.setImageDrawable(null);
this.imageView.setImageDrawable(null);
return;
}

imageView.setImageBitmap(bitmap);
// Apply the image to the view.
if (this.isImageRippleEnabled) {
BitmapDrawable bitmapDrawable = new BitmapDrawable(this.imageView.getContext().getResources(), bitmap);
this.imageView.setImageDrawable(
new RippleDrawable(ColorStateList.valueOf(this.imageRippleColor), bitmapDrawable, null));
} else {
this.imageView.setImageBitmap(bitmap);
}
}

public void setOnClickListener(OnClickListener clickListener)
Expand Down
Expand Up @@ -41,8 +41,6 @@
import ti.modules.titanium.ui.ScrollViewProxy;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
Expand Down Expand Up @@ -813,6 +811,14 @@ public void processProperties(KrollDict d)
if (d.containsKey(TiC.PROPERTY_DEFAULT_IMAGE)) {
setDefaultImageSource(d.get(TiC.PROPERTY_DEFAULT_IMAGE));
}
if (d.containsKey(TiC.PROPERTY_IMAGE_TOUCH_FEEDBACK_COLOR)) {
String colorString = TiConvert.toString(d.get(TiC.PROPERTY_IMAGE_TOUCH_FEEDBACK_COLOR));
view.setImageRippleColor(
(colorString != null) ? TiConvert.toColor(colorString) : view.getDefaultRippleColor());
}
if (d.containsKey(TiC.PROPERTY_IMAGE_TOUCH_FEEDBACK)) {
view.setIsImageRippleEnabled(TiConvert.toBoolean(d.get(TiC.PROPERTY_IMAGE_TOUCH_FEEDBACK), false));
}
if (d.containsKey(TiC.PROPERTY_IMAGE)) {
// processProperties is also called from TableView, we need check if we changed before re-creating the
// bitmap
Expand Down Expand Up @@ -868,6 +874,12 @@ public void propertyChanged(String key, Object oldValue, Object newValue, KrollP

if (key.equals(TiC.PROPERTY_ENABLE_ZOOM_CONTROLS)) {
view.setEnableZoomControls(TiConvert.toBoolean(newValue));
} else if (key.equals(TiC.PROPERTY_IMAGE_TOUCH_FEEDBACK)) {
view.setIsImageRippleEnabled(TiConvert.toBoolean(newValue, false));
} else if (key.equals(TiC.PROPERTY_IMAGE_TOUCH_FEEDBACK_COLOR)) {
String colorString = TiConvert.toString(newValue);
view.setImageRippleColor(
(colorString != null) ? TiConvert.toColor(colorString) : view.getDefaultRippleColor());
} else if (key.equals(TiC.PROPERTY_IMAGE)) {
if ((oldValue == null && newValue != null) || (oldValue != null && !oldValue.equals(newValue))) {
TiDrawableReference source = TiDrawableReference.fromObject(getProxy(), newValue);
Expand Down Expand Up @@ -961,18 +973,15 @@ public TiBlob toBlob()
} else {
TiImageView view = getView();
if (view != null) {
Drawable drawable = view.getImageDrawable();
if (drawable instanceof BitmapDrawable) {
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
if (bitmap == null && imageSources != null && imageSources.size() == 1) {
bitmap = imageSources.get(0).getBitmap(true);
}
if (bitmap != null) {
if (imageReference != null) {
mMemoryCache.put(imageReference.hashCode(), bitmap);
}
return TiBlob.blobFromImage(bitmap);
Bitmap bitmap = view.getImageBitmap();
if (bitmap == null && imageSources != null && imageSources.size() == 1) {
bitmap = imageSources.get(0).getBitmap(true);
}
if (bitmap != null) {
if (imageReference != null) {
mMemoryCache.put(imageReference.hashCode(), bitmap);
}
return TiBlob.blobFromImage(bitmap);
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions android/titanium/src/java/org/appcelerator/titanium/TiC.java
Expand Up @@ -473,6 +473,8 @@ public class TiC
public static final String PROPERTY_ICONIFIED_BY_DEFAULT = "iconifiedByDefault";
public static final String PROPERTY_ID = "id";
public static final String PROPERTY_IMAGE = "image";
public static final String PROPERTY_IMAGE_TOUCH_FEEDBACK = "imageTouchFeedback";
public static final String PROPERTY_IMAGE_TOUCH_FEEDBACK_COLOR = "imageTouchFeedbackColor";
public static final String PROPERTY_IMAGES = "images";
public static final String PROPERTY_IMPORTANCE = "importance";
public static final String PROPERTY_INDICATOR_COLOR = "indicatorColor";
Expand Down
19 changes: 19 additions & 0 deletions apidoc/Titanium/UI/ImageView.yml
Expand Up @@ -201,6 +201,25 @@ properties:
for more information.
type: [ String, Titanium.Blob, Titanium.Filesystem.File ]

- name: imageTouchFeedback
summary: Enables a ripple effect when the foreground image is touched.
description: |
Note that the [touchFeedback](Titanium.UI.View.touchFeedback) property applies a ripple effect to the
view's background. If the image is opaque and completely covers the view (such as a photo),
then the background's ripple won't be visible. In this case, you should use this `imageTouchFeedback`
property to apply a ripple effect to the foreground image assigned via the `image` property.
type: Boolean
default: false
platforms: [android]
since: "10.1.0"

- name: imageTouchFeedbackColor
summary: Optional touch feedback ripple color. This has no effect unless `imageTouchFeedback` is true.
description: Defaults to provided theme color.
type: String
platforms: [android]
since: "10.1.0"

- name: images
summary: |
Array of images to animate, defined using local filesystem paths, `File` objects,
Expand Down
24 changes: 24 additions & 0 deletions tests/Resources/ti.ui.imageview.test.js
Expand Up @@ -253,6 +253,30 @@ describe('Titanium.UI.ImageView', function () {
});
});

describe.android('.imageTouchFeedback', () => {
function test(imageViewProperties, finish) {
win = Ti.UI.createWindow();
win.add(Ti.UI.createImageView(imageViewProperties));
win.addEventListener('postlayout', function listener() {
win.removeEventListener('postlayout', listener);
finish();
});
win.open();
}

it('without image', function (finish) {
test({ imageTouchFeedback: true }, finish);
});

it('with image', function (finish) {
test({ image: 'Logo.png', imageTouchFeedback: true }, finish);
});

it('with imageTouchFeedbackColor', function (finish) {
test({ image: 'Logo.png', imageTouchFeedback: true, imageTouchFeedbackColor: 'yellow' }, finish);
});
});

// TODO: Combine all tests for 'images' property into one suite
// TODO Make this test cross-platform. We're using ms-appx urls here
it.windows('images', function (finish) {
Expand Down

0 comments on commit b2e84bd

Please sign in to comment.