Skip to content

Commit

Permalink
Change default anchor to center. Simplify code.
Browse files Browse the repository at this point in the history
Changing the WearCurvedTextView's default anchorType to center, means we
can simplify the contract between the arc layout and the curved text,
the curved text by default draws itself x-centered at the top, and the
parent arc layout can rotate it to where it needs to be.

Relnote: Change WearCurvedTextView's anchor type default to center.
Test: Updated

Change-Id: I105ff40f39488f960582a7cba799e47b6b7086ee
  • Loading branch information
ssancho14 committed Nov 27, 2020
1 parent 9dece73 commit 2798931
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 99 deletions.
6 changes: 2 additions & 4 deletions wear/wear/api/current.txt
Expand Up @@ -316,10 +316,9 @@ package androidx.wear.widget {
}

public static interface WearArcLayout.ArcLayoutWidget {
method public void checkInvalidAttributeAsChild(boolean);
method public void checkInvalidAttributeAsChild();
method public float getSweepAngleDegrees();
method public int getThicknessPx();
method public boolean handleLayoutRotate(float);
method public boolean insideClickArea(float, float);
}

Expand All @@ -341,7 +340,7 @@ package androidx.wear.widget {
ctor public WearCurvedTextView(android.content.Context, android.util.AttributeSet?);
ctor public WearCurvedTextView(android.content.Context, android.util.AttributeSet?, int);
ctor public WearCurvedTextView(android.content.Context, android.util.AttributeSet?, int, int);
method public void checkInvalidAttributeAsChild(boolean);
method public void checkInvalidAttributeAsChild();
method public float getAnchorAngleDegrees();
method public int getAnchorType();
method public boolean getClockwise();
Expand All @@ -357,7 +356,6 @@ package androidx.wear.widget {
method public float getTextSize();
method public int getThicknessPx();
method public android.graphics.Typeface? getTypeface();
method public boolean handleLayoutRotate(float);
method public boolean insideClickArea(float, float);
method public void setAnchorAngleDegrees(float);
method public void setAnchorType(int);
Expand Down
6 changes: 2 additions & 4 deletions wear/wear/api/public_plus_experimental_current.txt
Expand Up @@ -316,10 +316,9 @@ package androidx.wear.widget {
}

public static interface WearArcLayout.ArcLayoutWidget {
method public void checkInvalidAttributeAsChild(boolean);
method public void checkInvalidAttributeAsChild();
method public float getSweepAngleDegrees();
method public int getThicknessPx();
method public boolean handleLayoutRotate(float);
method public boolean insideClickArea(float, float);
}

Expand All @@ -341,7 +340,7 @@ package androidx.wear.widget {
ctor public WearCurvedTextView(android.content.Context, android.util.AttributeSet?);
ctor public WearCurvedTextView(android.content.Context, android.util.AttributeSet?, int);
ctor public WearCurvedTextView(android.content.Context, android.util.AttributeSet?, int, int);
method public void checkInvalidAttributeAsChild(boolean);
method public void checkInvalidAttributeAsChild();
method public float getAnchorAngleDegrees();
method public int getAnchorType();
method public boolean getClockwise();
Expand All @@ -357,7 +356,6 @@ package androidx.wear.widget {
method public float getTextSize();
method public int getThicknessPx();
method public android.graphics.Typeface? getTypeface();
method public boolean handleLayoutRotate(float);
method public boolean insideClickArea(float, float);
method public void setAnchorAngleDegrees(float);
method public void setAnchorType(int);
Expand Down
6 changes: 2 additions & 4 deletions wear/wear/api/restricted_current.txt
Expand Up @@ -320,10 +320,9 @@ package androidx.wear.widget {
}

public static interface WearArcLayout.ArcLayoutWidget {
method public void checkInvalidAttributeAsChild(boolean);
method public void checkInvalidAttributeAsChild();
method public float getSweepAngleDegrees();
method public int getThicknessPx();
method public boolean handleLayoutRotate(float);
method public boolean insideClickArea(float, float);
}

Expand All @@ -348,7 +347,7 @@ package androidx.wear.widget {
ctor public WearCurvedTextView(android.content.Context, android.util.AttributeSet?);
ctor public WearCurvedTextView(android.content.Context, android.util.AttributeSet?, int);
ctor public WearCurvedTextView(android.content.Context, android.util.AttributeSet?, int, int);
method public void checkInvalidAttributeAsChild(boolean);
method public void checkInvalidAttributeAsChild();
method public float getAnchorAngleDegrees();
method public int getAnchorType();
method public boolean getClockwise();
Expand All @@ -364,7 +363,6 @@ package androidx.wear.widget {
method public float getTextSize();
method public int getThicknessPx();
method public android.graphics.Typeface? getTypeface();
method public boolean handleLayoutRotate(float);
method public boolean insideClickArea(float, float);
method public void setAnchorAngleDegrees(float);
method public void setAnchorType(@androidx.wear.widget.WearArcLayout.AnchorType int);
Expand Down
Expand Up @@ -227,12 +227,14 @@ class WearCurvedTextViewTest {
text = "This is a clockwise text for testing background"
clockwise = true
anchorAngleDegrees = 170.0f
anchorType = WearArcLayout.ANCHOR_START
setBackgroundColor(Color.rgb(0, 100, 100))
},
WearCurvedTextView(ApplicationProvider.getApplicationContext()).apply {
text = "Another clockwise text"
clockwise = true
anchorAngleDegrees = 70.0f
anchorType = WearArcLayout.ANCHOR_START
setBackgroundColor(Color.rgb(0, 100, 100))
}
)
Expand All @@ -249,12 +251,14 @@ class WearCurvedTextViewTest {
text = "This is a counterclockwise text for testing background"
clockwise = false
anchorAngleDegrees = 100.0f
anchorType = WearArcLayout.ANCHOR_START
setBackgroundColor(Color.rgb(0, 100, 100))
},
WearCurvedTextView(ApplicationProvider.getApplicationContext()).apply {
text = "Another counterclockwise text"
clockwise = false
anchorAngleDegrees = 230.0f
anchorType = WearArcLayout.ANCHOR_START
setBackgroundColor(Color.rgb(0, 100, 100))
}
)
Expand Down
57 changes: 18 additions & 39 deletions wear/wear/src/main/java/androidx/wear/widget/WearArcLayout.java
Expand Up @@ -92,17 +92,8 @@ public interface ArcLayoutWidget {

/**
* Check whether the widget contains invalid attributes as a child of WearArcLayout
*
* @param clockwise the layout direction of the container
*/
void checkInvalidAttributeAsChild(boolean clockwise);

/**
* Return whether the widget will handle the layout rotation requested by the container
* If return true, make sure that the layout rotation is done inside the widget since the
* container will skip this process.
*/
boolean handleLayoutRotate(float angle);
void checkInvalidAttributeAsChild();

/**
* Return true when the given point is in the clickable area of the child widget.
Expand Down Expand Up @@ -563,42 +554,30 @@ protected boolean drawChild(@NonNull Canvas canvas, @NonNull View child, long dr
mTouchedViewAngle = middleAngle;
}

// Rotate the child widget.
canvas.rotate(
multiplier * (mCurrentCumulativeAngle + preRotation),
getMeasuredWidth() / 2f,
getMeasuredHeight() / 2f);

if (child instanceof ArcLayoutWidget) {
ArcLayoutWidget childWidget = (ArcLayoutWidget) child;
childWidget.checkInvalidAttributeAsChild(mClockwise);

// Special case for ArcLayoutWidget. This doesn't need pre-rotating to get the center
// of canvas lines up, as it should already know how to draw itself correctly from
// the "current" rotation. The layout rotation is always passed to the child widget,
// if the child has not handled this rotation by itself, the parent will have to
// rotate the canvas to apply this layout.
if (!childWidget.handleLayoutRotate(multiplier * mCurrentCumulativeAngle)) {
canvas.rotate(
multiplier * mCurrentCumulativeAngle,
getMeasuredWidth() / 2f,
getMeasuredHeight() / 2f
);
}
((ArcLayoutWidget) child).checkInvalidAttributeAsChild();
} else {
canvas.rotate(
multiplier * (mCurrentCumulativeAngle + preRotation),
getMeasuredWidth() / 2f,
getMeasuredHeight() / 2f);

// Do we need to do some counter rotation?
LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();

// For counterclockwise layout, especially when mixing standard Android widget with
// ArcLayoutWidget as children, we might need to rotate the standard widget to make
// them with the same upwards direction.
float angleToRotate = 0f;
if (layoutParams.getRotate() && !mClockwise) {
angleToRotate = 180f;
}

// Un-rotate about the top of the canvas, around the center of the actual child.
// This compounds with the initial rotation into a translation.
if (!layoutParams.getRotate()) {
if (layoutParams.getRotate()) {
// For counterclockwise layout, especially when mixing standard Android widget with
// ArcLayoutWidget as children, we might need to rotate the standard widget to make
// them have the same upwards direction.
if (!mClockwise) {
angleToRotate = 180f;
}
} else {
// Un-rotate about the top of the canvas, around the center of the actual child.
// This compounds with the initial rotation into a translation.
angleToRotate = -multiplier * (mCurrentCumulativeAngle + preRotation);
}

Expand Down
Expand Up @@ -77,12 +77,8 @@ public class WearCurvedTextView extends View implements WearArcLayout.ArcLayoutW
private float mPathRadius = 0f;
private float mTextSweepDegrees = 0f;
private float mBackgroundSweepDegrees = MAX_SWEEP_DEGREE;
private boolean mHasParentArcLayout = false;
private boolean mParentClockwise = true;
private int mLastUsedTextAlignment = -1;
private float mLocalRotateAngle = 0f;
private float mParentRotateAngle = 0f;
private boolean mParentRotateAngleSet = false;

private int mAnchorType = UNSET_ANCHOR_TYPE;
private float mAnchorAngleDegrees = UNSET_ANCHOR_DEGREE;
Expand Down Expand Up @@ -215,10 +211,7 @@ public int getThicknessPx() {
* were set for a widget in WearArcLayout
*/
@Override
public void checkInvalidAttributeAsChild(boolean parentClockwise) {
this.mHasParentArcLayout = true;
this.mParentClockwise = parentClockwise;

public void checkInvalidAttributeAsChild() {
if (mAnchorType != UNSET_ANCHOR_TYPE) {
throw new IllegalArgumentException(
"WearCurvedTextView shall not set anchorType value when added into"
Expand All @@ -234,18 +227,6 @@ public void checkInvalidAttributeAsChild(boolean parentClockwise) {
}
}

@Override
public boolean handleLayoutRotate(float angle) {
mParentRotateAngleSet = true;

// Ensure we are redrawn when the parent rotates.
if (mParentRotateAngle != angle) {
doRedraw();
}
mParentRotateAngle = angle;
return true;
}

@Override
public boolean insideClickArea(float x, float y) {
float radius2 = min(getWidth(), getHeight()) / 2f
Expand Down Expand Up @@ -340,8 +321,6 @@ private void updatePathsIfNeeded(boolean withBackground) {
}

float clockwiseFactor = mClockwise ? 1f : -1f;
float parentClockwiseFactor =
mHasParentArcLayout ? (mParentClockwise ? 1f : -1f) : clockwiseFactor;

float alignmentFactor = 0.5f;
switch (getTextAlignment()) {
Expand All @@ -357,31 +336,25 @@ private void updatePathsIfNeeded(boolean withBackground) {
alignmentFactor = 0.5f; // TEXT_ALIGNMENT_CENTER
}

float anchorTypeFactor = 0f;
float anchorTypeFactor;
switch (mAnchorType) {
case WearArcLayout.ANCHOR_START:
anchorTypeFactor = 0f;
break;
case WearArcLayout.ANCHOR_CENTER:
anchorTypeFactor = 0.5f;
break;
case WearArcLayout.ANCHOR_END:
anchorTypeFactor = 1f;
anchorTypeFactor = -0.5f;
break;
case WearArcLayout.ANCHOR_CENTER: // Center is the default.
default:
anchorTypeFactor = parentClockwiseFactor == clockwiseFactor ? 0f : -1f;
anchorTypeFactor = 0f;
}

float actualAnchorDegree =
(mAnchorAngleDegrees == UNSET_ANCHOR_DEGREE ? 0f : mAnchorAngleDegrees)
+ ANCHOR_DEGREE_OFFSET;
mLocalRotateAngle = (mAnchorAngleDegrees == UNSET_ANCHOR_DEGREE ? 0f : mAnchorAngleDegrees)
+ clockwiseFactor * anchorTypeFactor * mBackgroundSweepDegrees;

// Always draw the curved text on top center, then rotate the canvas to the right position
float backgroundStartAngle =
-clockwiseFactor * 0.5f * mBackgroundSweepDegrees + ANCHOR_DEGREE_OFFSET;
mLocalRotateAngle =
actualAnchorDegree - backgroundStartAngle
- parentClockwiseFactor * anchorTypeFactor * mBackgroundSweepDegrees;

float textStartAngle =
backgroundStartAngle + clockwiseFactor * (float) (
Expand Down Expand Up @@ -462,20 +435,15 @@ public boolean onTouchEvent(@NonNull MotionEvent event) {
return false;
}

float x0 = event.getX();
float y0 = event.getY();
if (!mParentRotateAngleSet) {
// If we are a stand-alone widget, we have to handle our rotation / anchor placement,
// if we are part of an arc container, it's handled by it.
double rotAngle = -Math.toRadians(mLocalRotateAngle);
float x0 = event.getX() - getWidth() / 2;
float y0 = event.getY() - getHeight() / 2;

x0 -= getWidth() / 2;
y0 -= getHeight() / 2;
float tempX = (float)
((x0 * cos(rotAngle) - y0 * sin(rotAngle)) + getWidth() / 2);
y0 = (float) ((x0 * sin(rotAngle) + y0 * cos(rotAngle)) + getHeight() / 2);
x0 = tempX;
}
double rotAngle = -Math.toRadians(mLocalRotateAngle);

float tempX = (float)
((x0 * cos(rotAngle) - y0 * sin(rotAngle)) + getWidth() / 2);
y0 = (float) ((x0 * sin(rotAngle) + y0 * cos(rotAngle)) + getHeight() / 2);
x0 = tempX;

// Should we start handling the touch events?
if (!mHandlingTouch && insideClickArea(x0, y0)) {
Expand Down Expand Up @@ -503,7 +471,7 @@ public void draw(@NonNull Canvas canvas) {
boolean withBackground = getBackground() != null;
updatePathsIfNeeded(withBackground);
canvas.rotate(
mLocalRotateAngle + mParentRotateAngle,
mLocalRotateAngle,
getWidth() / 2f,
getHeight() / 2f);

Expand Down

0 comments on commit 2798931

Please sign in to comment.