Color animation
Closed this issue · 7 comments
Hi,
I've noticed you have the HSV animation issue.
How about trying this algorithm?
The animation you mentioned is so great. I will update my stupid HSV animation ASAP. Thanks for your notification~
@konmik
Hey, I found that when I try to change color from green(#00ff00) to blue(#0000ff) with your algorithm. The transformation of color is strange. Did I get any mistakes when using the algorithm you provided?
My code in WoWoBackgroundColorAnimation:
public class WoWoBackgroundColorAnimation extends PageAnimation {
private EaseType easeType;
private boolean useSameEaseTypeBack = true;
private ColorChangeType colorChangeType;
private int targetColor;
private int fromColor;
private int targetA = -1;
private int targetR = -1;
private int targetG = -1;
private int targetB = -1;
private float[] targetHSV = new float[3];
private int fromA = -1;
private int fromR = -1;
private int fromG = -1;
private int fromB = -1;
private float[] fromHSV = new float[3];
/**
*
* @param page animation starting page
* @param startOffset animation starting offset
* @param endOffset animation ending offset
* @param fromColor original color
* @param targetColor target color
* @param colorChangeType how to change the color.
* For more information, please check the ColorChangeType.class
* @param easeType ease type.
* For more information, please check the EaseType.class
* @param useSameEaseTypeBack whether use the same ease type to back
*/
public WoWoBackgroundColorAnimation(
int page,
float startOffset,
float endOffset,
int fromColor,
int targetColor,
ColorChangeType colorChangeType,
EaseType easeType,
boolean useSameEaseTypeBack) {
setPage(page);
setStartOffset(startOffset);
setEndOffset(endOffset);
this.easeType = easeType;
this.useSameEaseTypeBack = useSameEaseTypeBack;
this.fromColor = fromColor;
this.targetColor = targetColor;
setARGBandHSV();
this.colorChangeType = colorChangeType;
}
private float lastPositionOffset = -1;
private boolean lastTimeIsExceed = false;
private boolean lastTimeIsLess = false;
@Override
public void play(View onView, float positionOffset) {
// if the positionOffset is less than the starting color,
// we should set onView to starting color
// otherwise there may be offsets between starting color and actually color
// if the last time we do this, just return
if (positionOffset <= getStartOffset()) {
if (lastTimeIsLess) return;
onView.setBackgroundColor(fromColor);
lastTimeIsLess = true;
return;
}
lastTimeIsLess = false;
// if the positionOffset exceeds the endOffset,
// we should set onView to target color
// otherwise there may be offsets between target color and actually color
// if the last time we do this, just return
if (positionOffset >= getEndOffset()) {
if (lastTimeIsExceed) return;
onView.setBackgroundColor(targetColor);
lastTimeIsExceed = true;
return;
}
lastTimeIsExceed = false;
// get the true offset
positionOffset = (positionOffset - getStartOffset()) / (getEndOffset() - getStartOffset());
float movementOffset;
if (lastPositionOffset == -1) {
// first movement
movementOffset = easeType.getOffset(positionOffset);
} else {
if (positionOffset < lastPositionOffset) {
// back
if (useSameEaseTypeBack) {
movementOffset = 1 - easeType.getOffset(1 - positionOffset);
} else {
movementOffset = easeType.getOffset(positionOffset);
}
} else {
// forward
movementOffset = easeType.getOffset(positionOffset);
}
}
lastPositionOffset = positionOffset;
if (colorChangeType == ColorChangeType.RGB) {
onView.setBackgroundColor(
Color.argb(
fromA + (int)((targetA - fromA) * movementOffset),
fromR + (int)((targetR - fromR) * movementOffset),
fromG + (int)((targetG - fromG) * movementOffset),
fromB + (int)((targetB - fromB) * movementOffset))
);
} else {
// onView.setBackgroundColor(Color.HSVToColor(new float[]{
// fromHSV[0] + (targetHSV[0] - fromHSV[0]) * movementOffset,
// fromHSV[1] + (targetHSV[1] - fromHSV[1]) * movementOffset,
// fromHSV[2] + (targetHSV[2] - fromHSV[2]) * movementOffset
// }));
onView.setBackgroundColor(Color.HSVToColor(toHSV(move(vector0, vector1, movementOffset))));
}
}
private void setARGBandHSV() {
targetA = Color.alpha(targetColor);
targetR = Color.red(targetColor);
targetG = Color.green(targetColor);
targetB = Color.blue(targetColor);
Color.colorToHSV(targetColor, targetHSV);
fromA = Color.alpha(fromColor);
fromR = Color.red(fromColor);
fromG = Color.green(fromColor);
fromB = Color.blue(fromColor);
Color.colorToHSV(fromColor, fromHSV);
this.vector0 = toVector(toHSV(fromColor));
this.vector1 = toVector(toHSV(targetColor));
}
private static final float ERROR = 0.001f;
private float[] vector0 = null;
private float[] vector1 = null;
public int with(float delta) {
if (delta <= 0)
return fromColor;
if (delta >= 1)
return targetColor;
return Color.HSVToColor(toHSV(move(vector0, vector1, delta)));
}
public static float[] move(float[] vector0, float[] vector1, float delta) {
float[] vector = new float[3];
vector[0] = (vector1[0] - vector0[0]) * delta + vector0[0];
vector[1] = (vector1[1] - vector0[1]) * delta + vector0[1];
vector[2] = (vector1[2] - vector0[2]) * delta + vector0[2];
return vector;
}
public static float[] toHSV(int color) {
float[] hsv = new float[3];
Color.colorToHSV(color, hsv);
return hsv;
}
public static float[] toVector(float[] hsv) {
float[] vector = new float[3];
double rad = Math.PI * hsv[0] / 180;
vector[0] = (float) Math.cos(rad) * hsv[1];
vector[1] = (float) Math.sin(rad) * hsv[1];
vector[2] = hsv[2];
return vector;
}
public static float[] toHSV(float[] vector) {
float[] hsv = new float[3];
hsv[1] = (float) Math.sqrt(vector[0] * vector[0] + vector[1] * vector[1]);
hsv[0] = hsv[1] < ERROR ? 0 :
(float) (Math.atan2(vector[1] / hsv[1], vector[0] / hsv[1]) * 180 / Math.PI);
hsv[2] = vector[2];
return hsv;
}
}
I just copied your algorithm behind the original codes.
The effect:
The color will change to red, and suddenly to blue.
Oh, I will try this today, thanks! :D
It looks that there is a bug somewhere in robolectric. I'll release a fix soon.
Android's HSVToColor
does not work with negative hue values.
Here is the fix:
Thank you for trying this algorithm! :) I think there is a way to improve it even more - I could decrease value while transforming from color to color to compensate the color intensity while it moves across the center.
Yep, good idea. And thanks for the rapid fix. I will try this later.