content: package com.romainpiel.shimmer;
  
  import android.content.res.TypedArray;
  import android.graphics.LinearGradient;
  import android.graphics.Matrix;
  import android.graphics.Paint;
  import android.graphics.Shader;
  import android.util.AttributeSet;
  import android.view.View;
  
  /**
   * Shimmer
   * User: romainpiel
   * Date: 10/03/2014
   * Time: 17:06
   */
  public class ShimmerViewHelper {
  
      public interface AnimationSetupCallback {
          void onSetupAnimation(View target);
      }
  
      private static final int DEFAULT_REFLECTION_COLOR = 0xFFFFFFFF;
  
      private View view;
      private Paint paint;
  
      // center position of the gradient
      private float gradientX;
  
      // shader applied on the text view
      // only null until the first global layout
      private LinearGradient linearGradient;
  
      // shader's local matrix
      // never null
      private Matrix linearGradientMatrix;
  
      private int primaryColor;
  
      // shimmer reflection color
      private int reflectionColor;
  
      // true when animating
      private boolean isShimmering;
  
      // true after first global layout
      private boolean isSetUp;
  
      // callback called after first global layout
      private AnimationSetupCallback callback;
  
      public ShimmerViewHelper(View view, Paint paint, AttributeSet attributeSet) {
          this.view = view;
          this.paint = paint;
          init(attributeSet);
      }
  
      public float getGradientX() {
          return gradientX;
      }
  
      public void setGradientX(float gradientX) {
          this.gradientX = gradientX;
          view.invalidate();
      }
  
      public boolean isShimmering() {
          return isShimmering;
      }
  
      public void setShimmering(boolean isShimmering) {
          this.isShimmering = isShimmering;
      }
  
      public boolean isSetUp() {
          return isSetUp;
      }
  
      public void setAnimationSetupCallback(AnimationSetupCallback callback) {
          this.callback = callback;
      }
  
      public int getPrimaryColor() {
          return primaryColor;
      }
  
      public void setPrimaryColor(int primaryColor) {
          this.primaryColor = primaryColor;
          if (isSetUp) {
              resetLinearGradient();
          }
      }
  
      public int getReflectionColor() {
          return reflectionColor;
      }
  
      public void setReflectionColor(int reflectionColor) {
          this.reflectionColor = reflectionColor;
          if (isSetUp) {
              resetLinearGradient();
          }
      }
  
      private void init(AttributeSet attributeSet) {
  
          reflectionColor = DEFAULT_REFLECTION_COLOR;
  
          if (attributeSet != null) {
              TypedArray a = view.getContext().obtainStyledAttributes(attributeSet, R.styleable.ShimmerView, 0, 0);
              if (a != null) {
                  try {
                      reflectionColor = a.getColor(R.styleable.ShimmerView_reflectionColor, DEFAULT_REFLECTION_COLOR);
                  } catch (Exception e) {
                      android.util.Log.e("ShimmerTextView", "Error while creating the view:", e);
                  } finally {
                      a.recycle();
                  }
              }
          }
  
          linearGradientMatrix = new Matrix();
      }
  
      private void resetLinearGradient() {
  
          // our gradient is a simple linear gradient from textColor to reflectionColor. its axis is at the center
          // when it's outside of the view, the outer color (textColor) will be repeated (Shader.TileMode.CLAMP)
          // initially, the linear gradient is positioned on the left side of the view
          linearGradient = new LinearGradient(-view.getWidth(), 0, 0, 0,
                  new int[]{
                          primaryColor,
                          reflectionColor,
                          primaryColor,
                  },
                  new float[]{
                          0,
                          0.5f,
                          1
                  },
                  Shader.TileMode.CLAMP
          );
  
          paint.setShader(linearGradient);
      }
  
      protected void onSizeChanged() {
  
          resetLinearGradient();
  
          if (!isSetUp) {
              isSetUp = true;
  
              if (callback != null) {
                  callback.onSetupAnimation(view);
              }
          }
      }
  
      /**
       * content of the wrapping view's onDraw(Canvas)
       * MUST BE CALLED BEFORE SUPER STATEMENT
       */
      public void onDraw() {
  
          // only draw the shader gradient over the text while animating
          if (isShimmering) {
  
              // first onDraw() when shimmering
              if (paint.getShader() == null) {
                  paint.setShader(linearGradient);
              }
  
              // translate the shader local matrix
              linearGradientMatrix.setTranslate(2 * gradientX, 0);
  
              // this is required in order to invalidate the shader's position
              linearGradient.setLocalMatrix(linearGradientMatrix);
  
          } else {
              // we're not animating, remove the shader from the paint
              paint.setShader(null);
          }
  
      }
  }
  