Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TIMOB-19578] Material design custom animations and touch feedback #8446

Merged
merged 2 commits into from
Sep 29, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions android/titanium/src/java/org/appcelerator/titanium/TiC.java
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,16 @@ public class TiC
*/
public static final String PROPERTY_BACKGROUND_SELECTED_IMAGE = "backgroundSelectedImage";

/**
* @module.api
*/
public static final String PROPERTY_TOUCH_FEEDBACK = "touchFeedback";

/**
* @module.api
*/
public static final String PROPERTY_TOUCH_FEEDBACK_COLOR = "touchFeedbackColor";

/**
* @module.api
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
"softKeyboardOnFocus", "transform", "elevation", "touchTestId",
"translationX", "translationY", "translationZ", "rotation", "rotationX", "rotationY", "scaleX", "scaleY",

TiC.PROPERTY_TRANSITION_NAME
TiC.PROPERTY_TOUCH_FEEDBACK, TiC.PROPERTY_TOUCH_FEEDBACK_COLOR, TiC.PROPERTY_TRANSITION_NAME
})
public abstract class TiViewProxy extends KrollProxy implements Handler.Callback
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,23 @@
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.RippleDrawable;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.view.ViewCompat;
import android.text.TextUtils;
import android.util.Pair;
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.KeyEvent;
Expand Down Expand Up @@ -769,6 +775,8 @@ public void propertyChanged(String key, Object oldValue, Object newValue, KrollP
} else if (key.startsWith(TiC.PROPERTY_BACKGROUND_PADDING)) {
Log.i(TAG, key + " not yet implemented.");
} else if (key.equals(TiC.PROPERTY_OPACITY)
|| key.equals(TiC.PROPERTY_TOUCH_FEEDBACK_COLOR)
|| key.equals(TiC.PROPERTY_TOUCH_FEEDBACK)
|| key.startsWith(TiC.PROPERTY_BACKGROUND_PREFIX)
|| key.startsWith(TiC.PROPERTY_BORDER_PREFIX)) {
// Update first before querying.
Expand All @@ -783,7 +791,12 @@ public void propertyChanged(String key, Object oldValue, Object newValue, KrollP
boolean hasGradient = hasGradient(d);
boolean nativeViewNull = (nativeView == null);

boolean requiresCustomBackground = hasImage || hasRepeat || hasColorState || hasBorder || hasGradient;
boolean requiresCustomBackground = hasImage || hasColorState || hasBorder || hasGradient;

// PROPERTY_BACKGROUND_REPEAT is implicitly passed as false though not used in JS. So check the truth value and proceed.
if (!requiresCustomBackground) {
requiresCustomBackground = requiresCustomBackground && d.optBoolean(TiC.PROPERTY_BACKGROUND_REPEAT, false);
}

if (!requiresCustomBackground) {
if (background != null) {
Expand All @@ -795,10 +808,14 @@ public void propertyChanged(String key, Object oldValue, Object newValue, KrollP
if (d.containsKeyAndNotNull(TiC.PROPERTY_BACKGROUND_COLOR)) {
Integer bgColor = TiConvert.toColor(d, TiC.PROPERTY_BACKGROUND_COLOR);
if (!nativeViewNull) {
nativeView.setBackgroundColor(bgColor);
// A bug only on Android 2.3 (TIMOB-14311).
if (Build.VERSION.SDK_INT < TiC.API_LEVEL_HONEYCOMB && proxy.hasProperty(TiC.PROPERTY_OPACITY)) {
setOpacity(TiConvert.toFloat(proxy.getProperty(TiC.PROPERTY_OPACITY), 1f));
if (canApplyTouchFeedback(d)) {
applyTouchFeedback(bgColor, d.containsKey(TiC.PROPERTY_TOUCH_FEEDBACK_COLOR) ? TiConvert.toColor(d, TiC.PROPERTY_TOUCH_FEEDBACK_COLOR) : null);
} else {
nativeView.setBackgroundColor(bgColor);
// A bug only on Android 2.3 (TIMOB-14311).
if (Build.VERSION.SDK_INT < TiC.API_LEVEL_HONEYCOMB && proxy.hasProperty(TiC.PROPERTY_OPACITY)) {
setOpacity(TiConvert.toFloat(proxy.getProperty(TiC.PROPERTY_OPACITY), 1f));
}
}
nativeView.postInvalidate();
}
Expand Down Expand Up @@ -962,17 +979,21 @@ public void processProperties(KrollDict d)
} else if (d.containsKey(TiC.PROPERTY_BACKGROUND_COLOR) && !nativeViewNull) {
bgColor = TiConvert.toColor(d, TiC.PROPERTY_BACKGROUND_COLOR);

// Set the background color on the view directly only
// if there is no border. If a border is present we must
// use the TiBackgroundDrawable.
if (hasBorder(d)) {
if (background == null) {
applyCustomBackground(false);
}
background.setBackgroundColor(bgColor);


if (canApplyTouchFeedback(d)) {
applyTouchFeedback(bgColor, d.containsKey(TiC.PROPERTY_TOUCH_FEEDBACK_COLOR) ? TiConvert.toColor(d, TiC.PROPERTY_TOUCH_FEEDBACK_COLOR) : null);
} else {
nativeView.setBackgroundColor(bgColor);
// Set the background color on the view directly only
// if there is no border. If a border is present we must
// use the TiBackgroundDrawable.
if (hasBorder(d)) {
if (background == null) {
applyCustomBackground(false);
}
background.setBackgroundColor(bgColor);
} else {
nativeView.setBackgroundColor(bgColor);
}
}
}

Expand Down Expand Up @@ -1091,6 +1112,33 @@ private void applyCustomBackground(boolean reuseCurrentDrawable)
}
}

/**
* @param props View's property dictionary
* @return true if touch feedback can be applied.
*/
protected boolean canApplyTouchFeedback(@NonNull KrollDict props) {
return ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) && props.optBoolean(TiC.PROPERTY_TOUCH_FEEDBACK, false) && !hasBorder(props));
}

/**
* Applies touch feedback. Should check canApplyTouchFeedback() before calling this.
* @param backgroundColor The background color of the view.
* @param rippleColor The ripple color.
*/
private void applyTouchFeedback(@NonNull Integer backgroundColor, @Nullable Integer rippleColor) {
if (rippleColor == null) {
Context context = TiApplication.getInstance();
TypedValue attribute = new TypedValue();
if (context.getTheme().resolveAttribute(android.R.attr.colorControlHighlight, attribute, true)) {
rippleColor = context.getResources().getColor(attribute.resourceId);
} else {
throw new RuntimeException("android.R.attr.colorControlHighlight cannot be resolved into Drawable");
}
}
RippleDrawable rippleDrawable = new RippleDrawable(ColorStateList.valueOf(rippleColor), new ColorDrawable(backgroundColor), null);
nativeView.setBackground(rippleDrawable);
}

public void onFocusChange(final View v, boolean hasFocus)
{
if (hasFocus) {
Expand Down
21 changes: 20 additions & 1 deletion apidoc/Titanium/UI/View.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1601,7 +1601,26 @@ properties:
description: If false, will forward the events to peers.
type: Boolean
default: true


- name: touchFeedback
summary: A material design visual construct that provides an instantaneous visual confirmation of touch point.
description: |
This is an opt-in feature available from Android Lollipop.
Touch feedback is applied only if the backgroundColor is a solid color.
type: Boolean
default: false
platforms: [android]
osver: {android: {min: "5.0"}}
since: "6.1.0"

- name: touchFeedbackColor
summary: Optional touch feedback ripple color. This has no effect unless `touchFeedback` is true.
type: String
default: Theme provided color.
platforms: [android]
osver: {android: {min: "5.0"}}
since: "6.1.0"

- name: transform
summary: Transformation matrix to apply to the view.
description: Android and Mobile Web only support 2DMatrix transforms.
Expand Down