Merge "Add ripple to switches, radio buttons, check boxes, seek bars"

This commit is contained in:
Alan Viverette
2014-04-23 02:19:20 +00:00
committed by Android (Google) Code Review
11 changed files with 176 additions and 57 deletions

View File

@@ -29,6 +29,8 @@ import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import com.android.internal.R;
public abstract class AbsSeekBar extends ProgressBar {
private Drawable mThumb;
private int mThumbOffset;
@@ -289,28 +291,39 @@ public abstract class AbsSeekBar extends ProgressBar {
*/
private void setThumbPos(int w, Drawable thumb, float scale, int gap) {
int available = w - mPaddingLeft - mPaddingRight;
int thumbWidth = thumb.getIntrinsicWidth();
int thumbHeight = thumb.getIntrinsicHeight();
final int thumbWidth = thumb.getIntrinsicWidth();
final int thumbHeight = thumb.getIntrinsicHeight();
available -= thumbWidth;
// The extra space for the thumb to move on the track
available += mThumbOffset * 2;
int thumbPos = (int) (scale * available + 0.5f);
final int thumbPos = (int) (scale * available + 0.5f);
int topBound, bottomBound;
final int top, bottom;
if (gap == Integer.MIN_VALUE) {
Rect oldBounds = thumb.getBounds();
topBound = oldBounds.top;
bottomBound = oldBounds.bottom;
final Rect oldBounds = thumb.getBounds();
top = oldBounds.top;
bottom = oldBounds.bottom;
} else {
topBound = gap;
bottomBound = gap + thumbHeight;
top = gap;
bottom = gap + thumbHeight;
}
// Canvas will be translated, so 0,0 is where we start drawing
final int left = (isLayoutRtl() && mMirrorForRtl) ? available - thumbPos : thumbPos;
thumb.setBounds(left, topBound, left + thumbWidth, bottomBound);
final int right = left + thumbWidth;
final Drawable background = getBackground();
if (background.supportsHotspots()) {
final Rect bounds = mThumb.getBounds();
final int offsetX = mPaddingLeft - mThumbOffset;
final int offsetY = mPaddingTop;
background.setHotspotBounds(left + offsetX, bounds.top + offsetY,
right + offsetX, bounds.bottom + offsetY);
}
// Canvas will be translated, so 0,0 is where we start drawing
thumb.setBounds(left, top, right, bottom);
}
/**
@@ -328,6 +341,7 @@ public abstract class AbsSeekBar extends ProgressBar {
@Override
protected synchronized void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mThumb != null) {
canvas.save();
// Translate the padding. For the x, we need to allow the thumb to
@@ -424,10 +438,24 @@ public abstract class AbsSeekBar extends ProgressBar {
return true;
}
private void setHotspot(int id, float x, float y) {
final Drawable bg = getBackground();
if (bg != null && bg.supportsHotspots()) {
bg.setHotspot(id, x, y);
}
}
private void clearHotspot(int id) {
final Drawable bg = getBackground();
if (bg != null && bg.supportsHotspots()) {
bg.removeHotspot(id);
}
}
private void trackTouchEvent(MotionEvent event) {
final int width = getWidth();
final int available = width - mPaddingLeft - mPaddingRight;
int x = (int)event.getX();
final int x = (int) event.getX();
float scale;
float progress = 0;
if (isLayoutRtl() && mMirrorForRtl) {
@@ -451,7 +479,8 @@ public abstract class AbsSeekBar extends ProgressBar {
}
final int max = getMax();
progress += scale * max;
setHotspot(R.attr.state_pressed, x, (int) event.getY());
setProgress((int) progress, true);
}
@@ -477,6 +506,7 @@ public abstract class AbsSeekBar extends ProgressBar {
* canceled.
*/
void onStopTrackingTouch() {
clearHotspot(R.attr.state_pressed);
mIsDragging = false;
}

View File

@@ -261,15 +261,13 @@ public abstract class CompoundButton extends Button implements Checkable {
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
final Drawable buttonDrawable = mButtonDrawable;
if (buttonDrawable != null) {
final int verticalGravity = getGravity() & Gravity.VERTICAL_GRAVITY_MASK;
final int drawableHeight = buttonDrawable.getIntrinsicHeight();
final int drawableWidth = buttonDrawable.getIntrinsicWidth();
int top = 0;
final int top;
switch (verticalGravity) {
case Gravity.BOTTOM:
top = getHeight() - drawableHeight;
@@ -277,12 +275,24 @@ public abstract class CompoundButton extends Button implements Checkable {
case Gravity.CENTER_VERTICAL:
top = (getHeight() - drawableHeight) / 2;
break;
default:
top = 0;
}
int bottom = top + drawableHeight;
int left = isLayoutRtl() ? getWidth() - drawableWidth : 0;
int right = isLayoutRtl() ? getWidth() : drawableWidth;
final int bottom = top + drawableHeight;
final int left = isLayoutRtl() ? getWidth() - drawableWidth : 0;
final int right = isLayoutRtl() ? getWidth() : drawableWidth;
buttonDrawable.setBounds(left, top, right, bottom);
final Drawable background = getBackground();
if (background.supportsHotspots()) {
background.setHotspotBounds(left, top, right, bottom);
}
}
super.onDraw(canvas);
if (buttonDrawable != null) {
buttonDrawable.draw(canvas);
}
}

View File

@@ -773,8 +773,6 @@ public class Switch extends CompoundButton {
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
final Rect tempRect = mTempRect;
final Drawable trackDrawable = mTrackDrawable;
final Drawable thumbDrawable = mThumbDrawable;
@@ -785,16 +783,12 @@ public class Switch extends CompoundButton {
final int switchRight = mSwitchRight;
final int switchBottom = mSwitchBottom;
trackDrawable.setBounds(switchLeft, switchTop, switchRight, switchBottom);
trackDrawable.draw(canvas);
final int saveCount = canvas.save();
trackDrawable.getPadding(tempRect);
final int switchInnerLeft = switchLeft + tempRect.left;
final int switchInnerTop = switchTop + tempRect.top;
final int switchInnerRight = switchRight - tempRect.right;
final int switchInnerBottom = switchBottom - tempRect.bottom;
canvas.clipRect(switchInnerLeft, switchTop, switchInnerRight, switchBottom);
// Relies on mTempRect, MUST be called first!
final int thumbPos = getThumbOffset();
@@ -803,6 +797,18 @@ public class Switch extends CompoundButton {
int thumbLeft = switchInnerLeft - tempRect.left + thumbPos;
int thumbRight = switchInnerLeft + thumbPos + mThumbWidth + tempRect.right;
thumbDrawable.setBounds(thumbLeft, switchTop, thumbRight, switchBottom);
final Drawable background = getBackground();
if (background.supportsHotspots()) {
background.setHotspotBounds(thumbLeft, switchTop, thumbRight, switchBottom);
}
super.onDraw(canvas);
trackDrawable.draw(canvas);
final int saveCount = canvas.save();
canvas.clipRect(switchInnerLeft, switchTop, switchInnerRight, switchBottom);
thumbDrawable.draw(canvas);
final int drawableState[] = getDrawableState();

View File

@@ -15,18 +15,20 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:state_enabled="true" android:state_pressed="true">
<bitmap android:src="@drawable/btn_radio_on_pressed_qntm_alpha"
android:tint="?attr/colorControlActivated" />
<item android:state_enabled="false" android:state_checked="true">
<bitmap android:src="@drawable/btn_radio_on_qntm_alpha"
android:tint="?attr/colorControlNormal"
android:alpha="?attr/disabledAlpha" />
</item>
<item android:state_enabled="false">
<bitmap android:src="@drawable/btn_radio_off_qntm_alpha"
android:tint="?attr/colorControlNormal"
android:alpha="?attr/disabledAlpha" />
</item>
<item android:state_checked="true">
<bitmap android:src="@drawable/btn_radio_on_qntm_alpha"
android:tint="?attr/colorControlActivated" />
</item>
<item android:state_enabled="true" android:state_pressed="true">
<bitmap android:src="@drawable/btn_radio_off_pressed_qntm_alpha"
android:tint="?attr/colorControlActivated" />
</item>
<item>
<bitmap android:src="@drawable/btn_radio_off_qntm_alpha"
android:tint="?attr/colorControlNormal" />

View File

@@ -19,10 +19,6 @@
<bitmap android:src="@drawable/scrubber_control_off_qntm_alpha"
android:tint="?attr/colorControlNormal" />
</item>
<item android:state_pressed="true">
<bitmap android:src="@drawable/scrubber_control_on_pressed_qntm_alpha"
android:tint="?attr/colorControlActivated" />
</item>
<item>
<bitmap android:src="@drawable/scrubber_control_on_qntm_alpha"
android:tint="?attr/colorControlActivated" />

View File

@@ -15,18 +15,20 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:state_pressed="true">
<item android:state_enabled="false" android:state_checked="true">
<nine-patch android:src="@drawable/switch_on_qntm_alpha"
android:tint="?attr/colorControlActivated" />
android:tint="?attr/colorControlNormal"
android:alpha="?attr/disabledAlpha" />
</item>
<item android:state_enabled="false">
<nine-patch android:src="@drawable/switch_off_qntm_alpha"
android:tint="?attr/colorControlNormal"
android:alpha="?attr/disabledAlpha" />
</item>
<item android:state_checked="true">
<nine-patch android:src="@drawable/switch_on_qntm_alpha"
android:tint="?attr/colorControlActivated" />
</item>
<item android:state_pressed="true">
<nine-patch android:src="@drawable/switch_off_qntm_alpha"
android:tint="?attr/colorControlActivated" />
</item>
<item>
<nine-patch android:src="@drawable/switch_off_qntm_alpha"
android:tint="?attr/colorControlNormal" />

View File

@@ -485,11 +485,18 @@ please see styles_device_defaults.xml.
</style>
<style name="Widget.Quantum.CompoundButton" parent="Widget.CompoundButton"/>
<style name="Widget.Quantum.CompoundButton.CheckBox" parent="Widget.CompoundButton.CheckBox"/>
<style name="Widget.Quantum.CompoundButton.RadioButton" parent="Widget.CompoundButton.RadioButton"/>
<style name="Widget.Quantum.CompoundButton.CheckBox" parent="Widget.CompoundButton.CheckBox">
<item name="background">?attr/selectableItemBackground</item>
</style>
<style name="Widget.Quantum.CompoundButton.RadioButton" parent="Widget.CompoundButton.RadioButton">
<item name="background">?attr/selectableItemBackground</item>
</style>
<style name="Widget.Quantum.CompoundButton.Star" parent="Widget.CompoundButton.Star">
<item name="button">@drawable/btn_star_quantum</item>
<item name="background">?attr/selectableItemBackground</item>
</style>
<style name="Widget.Quantum.CompoundButton.Switch">
@@ -501,6 +508,7 @@ please see styles_device_defaults.xml.
<item name="thumbTextPadding">12dip</item>
<item name="switchMinWidth">72dip</item>
<item name="switchPadding">16dip</item>
<item name="background">?attr/selectableItemBackground</item>
</style>
<style name="Widget.Quantum.EditText" parent="Widget.EditText"/>
@@ -619,6 +627,7 @@ please see styles_device_defaults.xml.
<item name="paddingStart">16dip</item>
<item name="paddingEnd">16dip</item>
<item name="mirrorForRtl">true</item>
<item name="background">?attr/selectableItemBackground</item>
</style>
<style name="Widget.Quantum.RatingBar" parent="Widget.RatingBar">
@@ -846,7 +855,15 @@ please see styles_device_defaults.xml.
<item name="popupBackground">?attr/colorBackground</item>
</style>
<style name="Widget.Quantum.Light.CompoundButton" parent="Widget.Quantum.CompoundButton"/>
<style name="Widget.Quantum.Light.CompoundButton.CheckBox" parent="Widget.Quantum.CompoundButton.CheckBox"/>
<style name="Widget.Quantum.Light.CompoundButton.RadioButton" parent="Widget.Quantum.CompoundButton.RadioButton"/>
<style name="Widget.Quantum.Light.CompoundButton.Star" parent="Widget.Quantum.CompoundButton.Star"/>
<style name="Widget.Quantum.Light.CompoundButton.Switch" parent="Widget.Quantum.CompoundButton.Switch">
<item name="switchTextAppearance">@style/TextAppearance.Quantum.Light.Widget.Switch</item>
</style>
<style name="Widget.Quantum.Light.ListView.DropDown" parent="Widget.Quantum.ListView.DropDown"/>
<style name="Widget.Quantum.Light.EditText" parent="Widget.Quantum.EditText"/>
<style name="Widget.Quantum.Light.ExpandableListView" parent="Widget.Quantum.ExpandableListView"/>
@@ -916,7 +933,6 @@ please see styles_device_defaults.xml.
<item name="maxHeight">16dip</item>
</style>
<style name="Widget.Quantum.Light.CompoundButton.RadioButton" parent="Widget.Quantum.CompoundButton.RadioButton"/>
<style name="Widget.Quantum.Light.ScrollView" parent="Widget.Quantum.ScrollView"/>
<style name="Widget.Quantum.Light.HorizontalScrollView" parent="Widget.Quantum.HorizontalScrollView"/>
@@ -932,7 +948,6 @@ please see styles_device_defaults.xml.
<style name="Widget.Quantum.Light.Spinner.DropDown" parent="Widget.Quantum.Spinner.DropDown"/>
<style name="Widget.Quantum.Light.Spinner.DropDown.ActionBar" parent="Widget.Quantum.Spinner.DropDown.ActionBar"/>
<style name="Widget.Quantum.Light.CompoundButton.Star" parent="Widget.Quantum.CompoundButton.Star"/>
<style name="Widget.Quantum.Light.TabWidget" parent="Widget.Quantum.TabWidget"/>
<style name="Widget.Quantum.Light.WebTextView" parent="Widget.Quantum.WebTextView"/>
<style name="Widget.Quantum.Light.WebView" parent="Widget.Quantum.WebView"/>
@@ -989,10 +1004,6 @@ please see styles_device_defaults.xml.
<item name="backgroundSplit">?attr/colorPrimary</item>
</style>
<style name="Widget.Quantum.Light.CompoundButton.Switch" parent="Widget.Quantum.CompoundButton.Switch">
<item name="switchTextAppearance">@style/TextAppearance.Quantum.Light.Widget.Switch</item>
</style>
<style name="Widget.Quantum.Light.FastScroll" parent="Widget.Quantum.FastScroll"/>
<style name="Widget.Quantum.Light.MediaRouteButton" parent="Widget.Quantum.MediaRouteButton">

View File

@@ -518,9 +518,16 @@ public abstract class Drawable {
public void removeHotspot(int key) {}
/**
* Removes all hotspots from the drawable.
* Immediately removes all hotspots from the drawable.
*/
public void clearHotspots() {}
/**
* Sets the bounds to which hotspots are constrained.
*
* @hide until we finalize these APIs
*/
public void setHotspotBounds(int left, int top, int right, int bottom) {}
/**
* Whether this drawable requests projection.

View File

@@ -290,6 +290,26 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
return false;
}
/**
* @hide
*/
@Override
public boolean isProjected() {
if (super.isProjected()) {
return true;
}
final ChildDrawable[] layers = mLayerState.mChildren;
final int N = mLayerState.mNum;
for (int i = 0; i < N; i++) {
if (layers[i].mDrawable.isProjected()) {
return true;
}
}
return false;
}
/**
* Add a new layer to this drawable. The new layer is identified by an id.

View File

@@ -139,8 +139,8 @@ class Ripple {
public boolean draw(Canvas c, Paint p) {
final Rect bounds = mBounds;
final Rect padding = mPadding;
final float dX = Math.max(mX, bounds.right - mX);
final float dY = Math.max(mY, bounds.bottom - mY);
final float dX = Math.max(mX - bounds.left, bounds.right - mX);
final float dY = Math.max(mY - bounds.top, bounds.bottom - mY);
final int maxRadius = (int) Math.ceil(Math.sqrt(dX * dX + dY * dY));
final float enterState = mEnterState;

View File

@@ -53,6 +53,9 @@ public class TouchFeedbackDrawable extends LayerDrawable {
private final Rect mTempRect = new Rect();
private final Rect mPaddingRect = new Rect();
/** Current ripple effect bounds, used to constrain ripple effects. */
private final Rect mHotspotBounds = new Rect();
/** Current drawing bounds, used to compute dirty region. */
private final Rect mDrawingBounds = new Rect();
@@ -83,6 +86,9 @@ public class TouchFeedbackDrawable extends LayerDrawable {
/** Whether the animation runnable has been posted. */
private boolean mAnimating;
/** Whether bounds are being overridden. */
private boolean mOverrideBounds;
TouchFeedbackDrawable() {
this(new TouchFeedbackState(null, null, null), null, null);
}
@@ -114,9 +120,22 @@ public class TouchFeedbackDrawable extends LayerDrawable {
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
if (!mOverrideBounds) {
mHotspotBounds.set(bounds);
}
onHotspotBoundsChange();
}
private void onHotspotBoundsChange() {
final int x = mHotspotBounds.centerX();
final int y = mHotspotBounds.centerY();
final int N = mActiveRipplesCount;
for (int i = 0; i < N; i++) {
if (mState.mPinned) {
mActiveRipples[i].move(x, y);
}
mActiveRipples[i].onBoundsChanged();
}
}
@@ -292,10 +311,10 @@ public class TouchFeedbackDrawable extends LayerDrawable {
final Ripple ripple = mTouchedRipples.get(id);
if (ripple == null) {
final Rect bounds = getBounds();
final Rect padding = mPaddingRect;
getPadding(padding);
final Rect bounds = mHotspotBounds;
if (mState.mPinned) {
x = bounds.exactCenterX();
y = bounds.exactCenterY();
@@ -308,7 +327,12 @@ public class TouchFeedbackDrawable extends LayerDrawable {
mActiveRipples[mActiveRipplesCount++] = newRipple;
mTouchedRipples.put(id, newRipple);
} else if (!mState.mPinned) {
} else if (mState.mPinned) {
final Rect bounds = mHotspotBounds;
x = bounds.exactCenterX();
y = bounds.exactCenterY();
ripple.move(x, y);
} else {
ripple.move(x, y);
}
@@ -338,6 +362,7 @@ public class TouchFeedbackDrawable extends LayerDrawable {
final int n = mTouchedRipples.size();
for (int i = 0; i < n; i++) {
// TODO: Use a fast exit, maybe just fade out?
mTouchedRipples.valueAt(i).animate().exit();
}
@@ -347,6 +372,16 @@ public class TouchFeedbackDrawable extends LayerDrawable {
}
}
/**
* @hide
*/
@Override
public void setHotspotBounds(int left, int top, int right, int bottom) {
mOverrideBounds = true;
mHotspotBounds.set(left, top, right, bottom);
onHotspotBoundsChange();
}
/**
* Schedules the next animation, if necessary.
*/