Mega Code Archive

 
Categories / Android / 2D Graphics
 

Extends View to create ColorCircle

/*   * Copyright (C) 2008 OpenIntents.org  *  * Licensed under the Apache License, Version 2.0 (the "License");  * you may not use this file except in compliance with the License.  * You may obtain a copy of the License at  *  *      http://www.apache.org/licenses/LICENSE-2.0  *  * Unless required by applicable law or agreed to in writing, software  * distributed under the License is distributed on an "AS IS" BASIS,  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  * See the License for the specific language governing permissions and  * limitations under the License.  */ //package org.openintents.widget; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PointF; import android.graphics.Shader; import android.graphics.SweepGradient; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; /**  * Interface for notifications of position change of slider.  *   * @author Peli  */  interface OnColorChangedListener {   /**    * This method is called when the user changed the color.    *     * This works in touch mode, by dragging the along the     * color circle with the finger.    */   void onColorChanged(View view, int newColor);      /**    * This method is called when the user clicks the center button.    *     * @param colorcircle    * @param newColor    */   void onColorPicked(View view, int newColor); } /**  * ColorCircle.  *   * @author Peli, based on API demo code.  *   */ public class ColorCircle extends View {     private float center_radius;     private final static float CENTER_RADIUS_SCALE = 0.4f;          private Paint mPaint;     private Paint mCenterPaint;     private int[] mColors;     private OnColorChangedListener mListener;   /**    * Constructor. This version is only needed for instantiating the object    * manually (not from a layout XML file).    *     * @param context    */   public ColorCircle(Context context) {     super(context);     init();   }   /**    * Construct object, initializing with any attributes we understand from a    * layout file.    *     * These attributes are defined in res/values/attrs.xml .    *     * @see android.view.View#View(android.content.Context,    *      android.util.AttributeSet, java.util.Map)    */   public ColorCircle(Context context, AttributeSet attrs) {     super(context, attrs);     // TODO what happens with inflateParams     init();   }   /**    * Initializes variables.    */   void init() {         mColors = new int[] {             0xFFFF0000, 0xFFFF00FF, 0xFF0000FF, 0xFF00FFFF, 0xFF00FF00,             0xFFFFFF00, 0xFFFF0000         };         Shader s = new SweepGradient(0, 0, mColors, null);                  mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);         mPaint.setShader(s);         mPaint.setStyle(Paint.Style.STROKE);                  mCenterPaint = new Paint(Paint.ANTI_ALIAS_FLAG);         mCenterPaint.setStrokeWidth(5);   }          private boolean mTrackingCenter;     private boolean mHighlightCenter;     @Override      protected void onDraw(Canvas canvas) {     float outer_radius = Math.min(getWidth(), getHeight())/2;      float touch_feedback_ring = center_radius + 2*mCenterPaint.getStrokeWidth();         float r = (outer_radius + touch_feedback_ring) / 2;                  canvas.translate(getWidth()/2, getHeight()/2);                  mPaint.setStrokeWidth(outer_radius - touch_feedback_ring);                  // This is the main "color ring"         canvas.drawCircle(0, 0, r, mPaint);                // This is the center "activation button" circle         canvas.drawCircle(0, 0, center_radius, mCenterPaint);                  if (mTrackingCenter) {             int c = mCenterPaint.getColor();             mCenterPaint.setStyle(Paint.Style.STROKE);                          if (mHighlightCenter) {                 mCenterPaint.setAlpha(0xFF);             } else {                 mCenterPaint.setAlpha(0x80);             }                          // The skinny ring around the center to indicate that it is being pressed             canvas.drawCircle(0, 0,                 center_radius + mCenterPaint.getStrokeWidth(),                               mCenterPaint);                          mCenterPaint.setStyle(Paint.Style.FILL);             mCenterPaint.setColor(c);         }     }        /**    * @see android.view.View#measure(int, int)    */   @Override   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {          int max_width = MeasureSpec.getSize(widthMeasureSpec);     int max_height = MeasureSpec.getSize(heightMeasureSpec);     int size = Math.min(max_width, max_height);     this.center_radius = CENTER_RADIUS_SCALE * size/2;          setMeasuredDimension(size, size);   }        public void setColor(int color) {         mCenterPaint.setColor(color);         invalidate();   }   public int getColor() {     return mCenterPaint.getColor();   }      public void setOnColorChangedListener(       OnColorChangedListener colorListener) {     mListener = colorListener;   }          private int ave(int s, int d, float p) {         return s + java.lang.Math.round(p * (d - s));     }          private int interpColor(int colors[], float unit) {         if (unit <= 0) {             return colors[0];         }         if (unit >= 1) {             return colors[colors.length - 1];         }                  float p = unit * (colors.length - 1);         int i = (int)p;         p -= i;         // now p is just the fractional part [0...1) and i is the index         int c0 = colors[i];         int c1 = colors[i+1];         int a = ave(Color.alpha(c0), Color.alpha(c1), p);         int r = ave(Color.red(c0), Color.red(c1), p);         int g = ave(Color.green(c0), Color.green(c1), p);         int b = ave(Color.blue(c0), Color.blue(c1), p);                  return Color.argb(a, r, g, b);     }          @Override     public boolean onTouchEvent(MotionEvent event) {         float x = event.getX() - getWidth()/2;         float y = event.getY() - getHeight()/2;         boolean inCenter = PointF.length(x, y) <= center_radius;                  switch (event.getAction()) {             case MotionEvent.ACTION_DOWN:                 mTrackingCenter = inCenter;                 if (inCenter) {                     mHighlightCenter = true;                     invalidate();                     break;                 }             case MotionEvent.ACTION_MOVE:                 if (mTrackingCenter) {                     if (mHighlightCenter != inCenter) {                         mHighlightCenter = inCenter;                         invalidate();                     }                 } else {                     float angle = (float)java.lang.Math.atan2(y, x);                     // need to turn angle [-PI ... PI] into unit [0....1]                     float unit = angle/(2*(float) Math.PI);                     if (unit < 0) {                         unit += 1;                     }                     int newcolor = interpColor(mColors, unit);                     mCenterPaint.setColor(newcolor);                   if (mListener != null) {                     mListener.onColorChanged(this, newcolor);                   }                     invalidate();                 }                 break;             case MotionEvent.ACTION_UP:                 if (mTrackingCenter) {                     if (inCenter) {                       if (mListener != null) {                         mListener.onColorPicked(this, mCenterPaint.getColor());                       }                     }                     mTrackingCenter = false;    // so we draw w/o halo                     invalidate();                 }                 break;         }         return true;     } }