2012年1月2日月曜日

ColorPicker の Action Provider を作った

色選択するための Action Provider を作りました。

HSV の領域をタッチして色を変えます。 SとVはそれぞれの現在値に応じて領域の色が変わるようになっています。



いつものように github にもおきましたー。
yanzm/ColorPickerActionProvider - GitHub -
  1. public class MainActivity extends Activity {  
  2.   
  3.     private int mSelectedColor = Color.BLACK;  
  4.   
  5.     @Override  
  6.     public boolean onCreateOptionsMenu(Menu menu) {  
  7.         super.onCreateOptionsMenu(menu);  
  8.         getMenuInflater().inflate(R.menu.menu, menu);  
  9.   
  10.         MenuItem item = menu.findItem(R.id.menu_color_picker);  
  11.   
  12.         HsvColorActionProvider actionProvider = (HsvColorActionProvider) item.getActionProvider();  
  13.   
  14.         actionProvider.setOnColorChangedListener(new HsvColorActionProvider.OnColorChangedListener() {  
  15.   
  16.             @Override  
  17.             public void onColorChanged(int color) {  
  18.                 View v = findViewById(android.R.id.content);  
  19.                 v.setBackgroundColor(color);  
  20.             }  
  21.   
  22.             @Override  
  23.             public void onColorSelected(int color) {  
  24.                 mSelectedColor = color;  
  25.                 View v = findViewById(android.R.id.content);  
  26.                 v.setBackgroundColor(color);  
  27.             }  
  28.   
  29.             @Override  
  30.             public void onCanceled() {  
  31.                 View v = findViewById(android.R.id.content);  
  32.                 v.setBackgroundColor(mSelectedColor);  
  33.             }  
  34.         });  
  35.   
  36.         return true;  
  37.     }  
  38. }  


  1. public class HsvColorActionProvider extends ActionProvider {  
  2.   
  3.     public interface OnColorChangedListener {  
  4.         public void onColorChanged(int color);  
  5.   
  6.         public void onColorSelected(int color);  
  7.   
  8.         public void onCanceled();  
  9.     }  
  10.   
  11.     private OnColorChangedListener mListener;  
  12.   
  13.     private Context mContext;  
  14.   
  15.     private LayoutInflater mLayoutInflater;  
  16.   
  17.     private PopupWindow mPopupWindow;  
  18.   
  19.     private HsvColorPickerView mColorPicker;  
  20.   
  21.     private int mInitialColor;  
  22.   
  23.     public HsvColorActionProvider(Context context) {  
  24.         super(context);  
  25.         mContext = context;  
  26.   
  27.         mInitialColor = Color.HSVToColor(new float[] { 1800.7f, 0.8f });  
  28.   
  29.         mLayoutInflater = LayoutInflater.from(context);  
  30.   
  31.         View v = mLayoutInflater.inflate(R.layout.color_popup, nullfalse);  
  32.   
  33.         mColorPicker = (HsvColorPickerView) v.findViewById(R.id.color_picker);  
  34.         mColorPicker.showPreview(true);  
  35.         mColorPicker.setIniticalColor(mInitialColor);  
  36.         mColorPicker.setOnColorChangedListener(new HsvColorPickerView.OnColorChangedListener() {  
  37.   
  38.             @Override  
  39.             public void onColorChanged(int color, float[] hsv) {  
  40.                 if (mListener != null) {  
  41.                     mListener.onColorChanged(color);  
  42.                 }  
  43.             }  
  44.         });  
  45.   
  46.         v.findViewById(R.id.cancel_btn).setOnClickListener(new View.OnClickListener() {  
  47.   
  48.             @Override  
  49.             public void onClick(View v) {  
  50.                 mPopupWindow.dismiss();  
  51.                 if (mListener != null) {  
  52.                     mListener.onCanceled();  
  53.                 }  
  54.             }  
  55.         });  
  56.   
  57.         v.findViewById(R.id.ok_btn).setOnClickListener(new View.OnClickListener() {  
  58.   
  59.             @Override  
  60.             public void onClick(View v) {  
  61.                 mInitialColor = mColorPicker.getCurrentColor();  
  62.                 if (mListener != null) {  
  63.                     mListener.onColorSelected(mInitialColor);  
  64.                 }  
  65.                 mPopupWindow.dismiss();  
  66.             }  
  67.         });  
  68.   
  69.         mPopupWindow = new PopupWindow(v);  
  70.         mPopupWindow.setBackgroundDrawable(mContext.getResources().getDrawable(R.drawable.panel_bg));  
  71.         mPopupWindow.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);  
  72.         mPopupWindow.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);  
  73.     }  
  74.   
  75.     public void setOnColorChangedListener(OnColorChangedListener l) {  
  76.         mListener = l;  
  77.     }  
  78.   
  79.     @Override  
  80.     public View onCreateActionView() {  
  81.   
  82.         LayoutInflater layoutInflater = LayoutInflater.from(mContext);  
  83.   
  84.         final View actionItem = layoutInflater.inflate(R.layout.color_action_provider, null);  
  85.   
  86.         ImageButton button = (ImageButton) actionItem.findViewById(R.id.button);  
  87.         button.setOnClickListener(new View.OnClickListener() {  
  88.             @Override  
  89.             public void onClick(View v) {  
  90.   
  91.                 if (!mPopupWindow.isShowing()) {  
  92.                     mColorPicker.setIniticalColor(mInitialColor);  
  93.                     mPopupWindow.showAsDropDown(actionItem);  
  94.                 } else {  
  95.                     mPopupWindow.dismiss();  
  96.                 }  
  97.             }  
  98.         });  
  99.   
  100.         return actionItem;  
  101.     }  
  102. }  


  1. public class HsvColorPickerView extends View {  
  2.   
  3.     public interface OnColorChangedListener {  
  4.         void onColorChanged(int color, float[] hsv);  
  5.     }  
  6.   
  7.     public void setOnColorChangedListener(OnColorChangedListener l) {  
  8.         mListener = l;  
  9.     }  
  10.   
  11.     /** 
  12.      * 初期カラーをセットする 
  13.      *  
  14.      * @param color 
  15.      */  
  16.     public void setIniticalColor(int color) {  
  17.         mCurrentColor = color;  
  18.         Color.colorToHSV(mCurrentColor, mCurrentHSV);  
  19.         invalidate();  
  20.     }  
  21.   
  22.     /** 
  23.      * 現在の色を返す 
  24.      *  
  25.      * @return 
  26.      */  
  27.     public int getCurrentColor() {  
  28.         return mCurrentColor;  
  29.     }  
  30.   
  31.     /** 
  32.      * プレビューを表示するかどうか 
  33.      *  
  34.      * @param show 
  35.      */  
  36.     public void showPreview(boolean show) {  
  37.         mIsShowPreview = show;  
  38.         updateRectArea();  
  39.     }  
  40.   
  41.     /** 
  42.      * 色領域の幅をセットする 
  43.      *  
  44.      * @param width 
  45.      */  
  46.     public void setRectWidth(int width) {  
  47.         mRectWidth = width;  
  48.         updateRectArea();  
  49.     }  
  50.   
  51.     /** 
  52.      * 色領域の高さをセットする 
  53.      *  
  54.      * @param height 
  55.      */  
  56.     public void setRectHeight(int height) {  
  57.         mRectHeight = height;  
  58.         updateRectArea();  
  59.     }  
  60.   
  61.     /** 
  62.      * 色領域間のギャップをセットする 
  63.      *  
  64.      * @param gap 
  65.      */  
  66.     public void setRectGap(int gap) {  
  67.         mRectGap = gap;  
  68.         updateRectArea();  
  69.     }  
  70.   
  71.     private static final int RECT_WIDTH = 400;  
  72.     private static final int RECT_HEIGHT = 80;  
  73.     private static final int RECT_GAP = 20;  
  74.   
  75.     private boolean mIsShowPreview = true;  
  76.   
  77.     private int mRectWidth = RECT_WIDTH;  
  78.     private int mRectHeight = RECT_HEIGHT;  
  79.     private int mRectGap = RECT_GAP;  
  80.   
  81.     private OnColorChangedListener mListener;  
  82.   
  83.     private int mCurrentColor = Color.RED;  
  84.     private float[] mCurrentHSV = new float[3];  
  85.   
  86.     private Shader mHueShader;  
  87.     private Shader mSaturationShader;  
  88.     private Shader mValueShader;  
  89.   
  90.     private Paint mHuePaint;  
  91.     private Paint mValuePaint;  
  92.     private Paint mSaturationPaint;  
  93.     private Paint mPreviewPaint;  
  94.     private Paint mLinePaint;  
  95.   
  96.     private Rect mHueRect;  
  97.     private Rect mSaturationRect;  
  98.     private Rect mValueRect;  
  99.     private Rect mPreviewRect;  
  100.   
  101.     int[] mHueList;  
  102.   
  103.     public HsvColorPickerView(Context c) {  
  104.         super(c);  
  105.         init();  
  106.     }  
  107.   
  108.     public HsvColorPickerView(Context context, AttributeSet attrs) {  
  109.         super(context, attrs);  
  110.         init();  
  111.     }  
  112.   
  113.     private void init() {  
  114.         Color.colorToHSV(mCurrentColor, mCurrentHSV);  
  115.   
  116.         mHueList = new int[10];  
  117.         float hue = 0;  
  118.         for (int i = 0; i < 10; i++) {  
  119.             mHueList[i] = setHSVColor(hue, 255255);  
  120.             hue += 36;  
  121.         }  
  122.   
  123.         mHuePaint = new Paint(Paint.ANTI_ALIAS_FLAG);  
  124.         mHuePaint.setStyle(Paint.Style.FILL);  
  125.         mHuePaint.setStrokeWidth(2);  
  126.   
  127.         mValuePaint = new Paint(Paint.ANTI_ALIAS_FLAG);  
  128.         mValuePaint.setStyle(Paint.Style.FILL);  
  129.         mValuePaint.setStrokeWidth(2);  
  130.   
  131.         mSaturationPaint = new Paint(Paint.ANTI_ALIAS_FLAG);  
  132.         mSaturationPaint.setStyle(Paint.Style.FILL);  
  133.         mSaturationPaint.setStrokeWidth(2);  
  134.   
  135.         mPreviewPaint = new Paint(Paint.ANTI_ALIAS_FLAG);  
  136.         mPreviewPaint.setStyle(Paint.Style.FILL);  
  137.         mPreviewPaint.setStrokeWidth(5);  
  138.   
  139.         mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);  
  140.         mLinePaint.setStyle(Paint.Style.FILL);  
  141.         mLinePaint.setStrokeWidth(5);  
  142.         mLinePaint.setColor(Color.BLACK);  
  143.   
  144.         updateRectArea();  
  145.     }  
  146.   
  147.     private void updateRectArea() {  
  148.         mHueShader = new LinearGradient(00, mRectWidth, 0, mHueList, null, Shader.TileMode.CLAMP);  
  149.         mHuePaint.setShader(mHueShader);  
  150.   
  151.         if (mIsShowPreview) {  
  152.             mPreviewRect = new Rect(00, mRectWidth, mRectHeight);  
  153.             mHueRect = new Rect(0, mRectHeight + mRectGap, mRectWidth, mRectHeight * 2 + mRectGap);  
  154.             mSaturationRect = new Rect(0, mRectHeight * 2 + mRectGap * 2, mRectWidth, mRectHeight * 3 + mRectGap * 2);  
  155.             mValueRect = new Rect(0, mRectHeight * 3 + mRectGap * 3, mRectWidth, mRectHeight * 4 + mRectGap * 3);  
  156.         } else {  
  157.             mHueRect = new Rect(00, mRectWidth, mRectHeight);  
  158.             mSaturationRect = new Rect(0, mRectHeight + mRectGap, mRectWidth, mRectHeight * 2 + mRectGap);  
  159.             mValueRect = new Rect(0, mRectHeight * 2 + mRectGap * 2, mRectWidth, mRectHeight * 3 + mRectGap * 2);  
  160.         }  
  161.     }  
  162.   
  163.     @Override  
  164.     protected void onDraw(Canvas canvas) {  
  165.   
  166.         // Hue  
  167.         canvas.drawRect(mHueRect, mHuePaint);  
  168.         canvas.drawLine(mCurrentHSV[0] * mRectWidth / 360, mHueRect.top, mCurrentHSV[0] * mRectWidth / 360,  
  169.                 mHueRect.bottom, mLinePaint);  
  170.   
  171.         // Saturation  
  172.         int[] mSaturationList = new int[10];  
  173.         float saturation = 0;  
  174.         for (int i = 0; i < 10; i++) {  
  175.             mSaturationList[i] = setHSVColor(mCurrentHSV[0], saturation, mCurrentHSV[2]);  
  176.             saturation += 0.1;  
  177.         }  
  178.         mSaturationShader = new LinearGradient(00, mRectWidth, 0, mSaturationList, null, Shader.TileMode.CLAMP);  
  179.         mSaturationPaint.setShader(mSaturationShader);  
  180.         canvas.drawRect(mSaturationRect, mSaturationPaint);  
  181.         canvas.drawLine(mCurrentHSV[1] * mRectWidth, mSaturationRect.top, mCurrentHSV[1] * mRectWidth,  
  182.                 mSaturationRect.bottom, mLinePaint);  
  183.   
  184.         // Value  
  185.         int[] mValueList = new int[10];  
  186.         float value = 0;  
  187.         for (int i = 0; i < 10; i++) {  
  188.             mValueList[i] = setHSVColor(mCurrentHSV[0], mCurrentHSV[1], value);  
  189.             value += 0.1;  
  190.         }  
  191.         mValueShader = new LinearGradient(00, mRectWidth, 0, mValueList, null, Shader.TileMode.CLAMP);  
  192.         mValuePaint.setShader(mValueShader);  
  193.         canvas.drawRect(mValueRect, mValuePaint);  
  194.         canvas.drawLine(mCurrentHSV[2] * mRectWidth, mValueRect.top, mCurrentHSV[2] * mRectWidth, mValueRect.bottom,  
  195.                 mLinePaint);  
  196.   
  197.         if (mIsShowPreview) {  
  198.             // Preview  
  199.             mPreviewPaint.setColor(mCurrentColor);  
  200.             canvas.drawRect(mPreviewRect, mPreviewPaint);  
  201.         }  
  202.     }  
  203.   
  204.     @Override  
  205.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  206.         if (mIsShowPreview) {  
  207.             setMeasuredDimension(mRectWidth, mRectHeight * 4 + mRectGap * 3);  
  208.         } else {  
  209.             setMeasuredDimension(mRectWidth, mRectHeight * 3 + mRectGap * 2);  
  210.         }  
  211.     }  
  212.   
  213.     private int setHSVColor(float hue, float saturation, float value) {  
  214.         float[] hsv = new float[3];  
  215.   
  216.         hsv[0] = Math.max(0, Math.min(359, hue));  
  217.         hsv[1] = Math.max(0, Math.min(1, saturation));  
  218.         hsv[2] = Math.max(0, Math.min(1, value));  
  219.   
  220.         return Color.HSVToColor(hsv);  
  221.     }  
  222.   
  223.     @Override  
  224.     public boolean onTouchEvent(MotionEvent event) {  
  225.         float x = event.getX();  
  226.         float y = event.getY();  
  227.   
  228.         boolean inHue = mHueRect.contains((int) x, (int) y);  
  229.         boolean inSaturation = mSaturationRect.contains((int) x, (int) y);  
  230.         boolean inValue = mValueRect.contains((int) x, (int) y);  
  231.   
  232.         switch (event.getAction()) {  
  233.             case MotionEvent.ACTION_DOWN:  
  234.             case MotionEvent.ACTION_MOVE:  
  235.                 if (inHue) {  
  236.                     float unit = x / mRectWidth;  
  237.                     mCurrentHSV[0] = Math.max(0, Math.min(unit * 360359));  
  238.                     updateCurrentColor();  
  239.   
  240.                 } else if (inSaturation) {  
  241.                     mCurrentHSV[1] = Math.max(0, Math.min(x / mRectWidth, 1));  
  242.                     updateCurrentColor();  
  243.   
  244.                 } else if (inValue) {  
  245.                     mCurrentHSV[2] = Math.max(0, Math.min(x / mRectWidth, 1));  
  246.                     updateCurrentColor();  
  247.                 }  
  248.                 break;  
  249.         }  
  250.         return true;  
  251.     }  
  252.   
  253.     private void updateCurrentColor() {  
  254.         mCurrentColor = Color.HSVToColor(mCurrentHSV);  
  255.         if (mListener != null) {  
  256.             mListener.onColorChanged(mCurrentColor, mCurrentHSV);  
  257.         }  
  258.         invalidate();  
  259.     }  
  260. }