Creating a Marquee Effect with Custom Drawable on Android
A custom drawable implementation for creating a marquee animation offers smootehr performance compared to traditional view-based approaches, primarily due to optimized color interpolation.
public class AnimatedGradientBorderDrawable extends Drawable {
private Paint borderPaint;
private RectF drawingBounds;
private RectF targetRect = new RectF();
private float cornerRadius = dpToPx(10);
private float strokeThickness = dpToPx(10);
private int purpleColor = Color.parseColor("#855bff");
private int blueColor = Color.parseColor("#3cfff8");
private int greenColor = Color.parseColor("#855bff");
private int yellowColor = Color.parseColor("#ffd220");
private int[] gradientColors = {purpleColor, blueColor, greenColor,
yellowColor, purpleColor, blueColor, greenColor,
yellowColor, purpleColor, blueColor, greenColor};
private int currentStrokeWidth;
private Matrix transformMatrix = new Matrix();
private float rotationAngle = 0f;
public AnimatedGradientBorderDrawable(int strokeWidth) {
this.currentStrokeWidth = strokeWidth;
initializePaint();
}
public float getRotation() {
return rotationAngle;
}
public void setRotation(float angle) {
rotationAngle = angle;
invalidateSelf();
}
private void initializePaint(){
borderPaint = new Paint();
borderPaint.setStyle(Paint.Style.STROKE);
if(currentStrokeWidth < 0){
borderPaint.setStrokeWidth(strokeThickness);
} else {
borderPaint.setStrokeWidth(currentStrokeWidth);
}
}
@Override
public void draw(@NonNull Canvas canvas) {
transformMatrix.reset();
transformMatrix.setRotate(rotationAngle, drawingBounds.centerX(), drawingBounds.centerY());
((SweepGradient)borderPaint.getShader()).setLocalMatrix(transformMatrix);
canvas.drawRect(targetRect, borderPaint);
}
@Override
public void setBounds(int left, int top, int right, int bottom) {
super.setBounds(left, top, right, bottom);
drawingBounds = new RectF(left, top, right, bottom);
targetRect.left = 0;
targetRect.top = 0;
targetRect.right = drawingBounds.width();
targetRect.bottom = drawingBounds.height();
SweepGradient gradient = new SweepGradient(drawingBounds.centerX(), drawingBounds.centerY(), gradientColors, null);
borderPaint.setShader(gradient);
}
@Override
public void setAlpha(int alpha) {
borderPaint.setAlpha(alpha);
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
borderPaint.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
private Property<AnimatedGradientBorderDrawable, Float> rotationProperty =
new Property<AnimatedGradientBorderDrawable, Float>(Float.class, "rotation") {
@Override
public Float get(AnimatedGradientBorderDrawable drawable) {
return drawable.getRotation();
}
@Override
public void set(AnimatedGradientBorderDrawable drawable, Float value) {
drawable.setRotation(value);
}
};
private ObjectAnimator animation;
public void startAnimation() {
animation = ObjectAnimator.ofFloat(this, rotationProperty, 0f, 360f);
animation.setDuration(10000L);
animation.setInterpolator(new LinearInterpolator());
animation.setRepeatCount(ValueAnimator.INFINITE);
animation.start();
}
public void stopAnimation() {
if (animation != null && animation.isRunning()) {
animation.cancel();
}
}
private float dpToPx(float dp) {
return dp * Resources.getSystem().getDisplayMetrics().density;
}
}
Usage example:
private void applyBackground(RelativeLayout container) {
AnimatedGradientBorderDrawable drawable = new AnimatedGradientBorderDrawable(paddingWidth);
drawable.setBounds(0, 0, screenWidth, screenHeight - statusBarHeight);
container.setBackground(drawable);
drawable.startAnimation();
}
The paddingWidth parameter controls the thickness of the animated border. Utilize utility functions for screan dimensions and status bar height.
public static int getStatusBarHeight(Context context) {
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
return context.getResources().getDimensionPixelSize(resourceId);
}
return 0;
}
This approach leverages canvas rotation and shader transformations to achieve smooth visual transitions.