HSV の領域をタッチして色を変えます。 SとVはそれぞれの現在値に応じて領域の色が変わるようになっています。
いつものように github にもおきましたー。
yanzm/ColorPickerActionProvider - GitHub -
public class MainActivity extends Activity {
private int mSelectedColor = Color.BLACK;
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.menu, menu);
MenuItem item = menu.findItem(R.id.menu_color_picker);
HsvColorActionProvider actionProvider = (HsvColorActionProvider) item.getActionProvider();
actionProvider.setOnColorChangedListener(new HsvColorActionProvider.OnColorChangedListener() {
@Override
public void onColorChanged(int color) {
View v = findViewById(android.R.id.content);
v.setBackgroundColor(color);
}
@Override
public void onColorSelected(int color) {
mSelectedColor = color;
View v = findViewById(android.R.id.content);
v.setBackgroundColor(color);
}
@Override
public void onCanceled() {
View v = findViewById(android.R.id.content);
v.setBackgroundColor(mSelectedColor);
}
});
return true;
}
}
public class HsvColorActionProvider extends ActionProvider {
public interface OnColorChangedListener {
public void onColorChanged(int color);
public void onColorSelected(int color);
public void onCanceled();
}
private OnColorChangedListener mListener;
private Context mContext;
private LayoutInflater mLayoutInflater;
private PopupWindow mPopupWindow;
private HsvColorPickerView mColorPicker;
private int mInitialColor;
public HsvColorActionProvider(Context context) {
super(context);
mContext = context;
mInitialColor = Color.HSVToColor(new float[] { 180, 0.7f, 0.8f });
mLayoutInflater = LayoutInflater.from(context);
View v = mLayoutInflater.inflate(R.layout.color_popup, null, false);
mColorPicker = (HsvColorPickerView) v.findViewById(R.id.color_picker);
mColorPicker.showPreview(true);
mColorPicker.setIniticalColor(mInitialColor);
mColorPicker.setOnColorChangedListener(new HsvColorPickerView.OnColorChangedListener() {
@Override
public void onColorChanged(int color, float[] hsv) {
if (mListener != null) {
mListener.onColorChanged(color);
}
}
});
v.findViewById(R.id.cancel_btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPopupWindow.dismiss();
if (mListener != null) {
mListener.onCanceled();
}
}
});
v.findViewById(R.id.ok_btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mInitialColor = mColorPicker.getCurrentColor();
if (mListener != null) {
mListener.onColorSelected(mInitialColor);
}
mPopupWindow.dismiss();
}
});
mPopupWindow = new PopupWindow(v);
mPopupWindow.setBackgroundDrawable(mContext.getResources().getDrawable(R.drawable.panel_bg));
mPopupWindow.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
mPopupWindow.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
}
public void setOnColorChangedListener(OnColorChangedListener l) {
mListener = l;
}
@Override
public View onCreateActionView() {
LayoutInflater layoutInflater = LayoutInflater.from(mContext);
final View actionItem = layoutInflater.inflate(R.layout.color_action_provider, null);
ImageButton button = (ImageButton) actionItem.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!mPopupWindow.isShowing()) {
mColorPicker.setIniticalColor(mInitialColor);
mPopupWindow.showAsDropDown(actionItem);
} else {
mPopupWindow.dismiss();
}
}
});
return actionItem;
}
}
public class HsvColorPickerView extends View {
public interface OnColorChangedListener {
void onColorChanged(int color, float[] hsv);
}
public void setOnColorChangedListener(OnColorChangedListener l) {
mListener = l;
}
/**
* 初期カラーをセットする
*
* @param color
*/
public void setIniticalColor(int color) {
mCurrentColor = color;
Color.colorToHSV(mCurrentColor, mCurrentHSV);
invalidate();
}
/**
* 現在の色を返す
*
* @return
*/
public int getCurrentColor() {
return mCurrentColor;
}
/**
* プレビューを表示するかどうか
*
* @param show
*/
public void showPreview(boolean show) {
mIsShowPreview = show;
updateRectArea();
}
/**
* 色領域の幅をセットする
*
* @param width
*/
public void setRectWidth(int width) {
mRectWidth = width;
updateRectArea();
}
/**
* 色領域の高さをセットする
*
* @param height
*/
public void setRectHeight(int height) {
mRectHeight = height;
updateRectArea();
}
/**
* 色領域間のギャップをセットする
*
* @param gap
*/
public void setRectGap(int gap) {
mRectGap = gap;
updateRectArea();
}
private static final int RECT_WIDTH = 400;
private static final int RECT_HEIGHT = 80;
private static final int RECT_GAP = 20;
private boolean mIsShowPreview = true;
private int mRectWidth = RECT_WIDTH;
private int mRectHeight = RECT_HEIGHT;
private int mRectGap = RECT_GAP;
private OnColorChangedListener mListener;
private int mCurrentColor = Color.RED;
private float[] mCurrentHSV = new float[3];
private Shader mHueShader;
private Shader mSaturationShader;
private Shader mValueShader;
private Paint mHuePaint;
private Paint mValuePaint;
private Paint mSaturationPaint;
private Paint mPreviewPaint;
private Paint mLinePaint;
private Rect mHueRect;
private Rect mSaturationRect;
private Rect mValueRect;
private Rect mPreviewRect;
int[] mHueList;
public HsvColorPickerView(Context c) {
super(c);
init();
}
public HsvColorPickerView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
Color.colorToHSV(mCurrentColor, mCurrentHSV);
mHueList = new int[10];
float hue = 0;
for (int i = 0; i < 10; i++) {
mHueList[i] = setHSVColor(hue, 255, 255);
hue += 36;
}
mHuePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mHuePaint.setStyle(Paint.Style.FILL);
mHuePaint.setStrokeWidth(2);
mValuePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mValuePaint.setStyle(Paint.Style.FILL);
mValuePaint.setStrokeWidth(2);
mSaturationPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mSaturationPaint.setStyle(Paint.Style.FILL);
mSaturationPaint.setStrokeWidth(2);
mPreviewPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPreviewPaint.setStyle(Paint.Style.FILL);
mPreviewPaint.setStrokeWidth(5);
mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mLinePaint.setStyle(Paint.Style.FILL);
mLinePaint.setStrokeWidth(5);
mLinePaint.setColor(Color.BLACK);
updateRectArea();
}
private void updateRectArea() {
mHueShader = new LinearGradient(0, 0, mRectWidth, 0, mHueList, null, Shader.TileMode.CLAMP);
mHuePaint.setShader(mHueShader);
if (mIsShowPreview) {
mPreviewRect = new Rect(0, 0, mRectWidth, mRectHeight);
mHueRect = new Rect(0, mRectHeight + mRectGap, mRectWidth, mRectHeight * 2 + mRectGap);
mSaturationRect = new Rect(0, mRectHeight * 2 + mRectGap * 2, mRectWidth, mRectHeight * 3 + mRectGap * 2);
mValueRect = new Rect(0, mRectHeight * 3 + mRectGap * 3, mRectWidth, mRectHeight * 4 + mRectGap * 3);
} else {
mHueRect = new Rect(0, 0, mRectWidth, mRectHeight);
mSaturationRect = new Rect(0, mRectHeight + mRectGap, mRectWidth, mRectHeight * 2 + mRectGap);
mValueRect = new Rect(0, mRectHeight * 2 + mRectGap * 2, mRectWidth, mRectHeight * 3 + mRectGap * 2);
}
}
@Override
protected void onDraw(Canvas canvas) {
// Hue
canvas.drawRect(mHueRect, mHuePaint);
canvas.drawLine(mCurrentHSV[0] * mRectWidth / 360, mHueRect.top, mCurrentHSV[0] * mRectWidth / 360,
mHueRect.bottom, mLinePaint);
// Saturation
int[] mSaturationList = new int[10];
float saturation = 0;
for (int i = 0; i < 10; i++) {
mSaturationList[i] = setHSVColor(mCurrentHSV[0], saturation, mCurrentHSV[2]);
saturation += 0.1;
}
mSaturationShader = new LinearGradient(0, 0, mRectWidth, 0, mSaturationList, null, Shader.TileMode.CLAMP);
mSaturationPaint.setShader(mSaturationShader);
canvas.drawRect(mSaturationRect, mSaturationPaint);
canvas.drawLine(mCurrentHSV[1] * mRectWidth, mSaturationRect.top, mCurrentHSV[1] * mRectWidth,
mSaturationRect.bottom, mLinePaint);
// Value
int[] mValueList = new int[10];
float value = 0;
for (int i = 0; i < 10; i++) {
mValueList[i] = setHSVColor(mCurrentHSV[0], mCurrentHSV[1], value);
value += 0.1;
}
mValueShader = new LinearGradient(0, 0, mRectWidth, 0, mValueList, null, Shader.TileMode.CLAMP);
mValuePaint.setShader(mValueShader);
canvas.drawRect(mValueRect, mValuePaint);
canvas.drawLine(mCurrentHSV[2] * mRectWidth, mValueRect.top, mCurrentHSV[2] * mRectWidth, mValueRect.bottom,
mLinePaint);
if (mIsShowPreview) {
// Preview
mPreviewPaint.setColor(mCurrentColor);
canvas.drawRect(mPreviewRect, mPreviewPaint);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mIsShowPreview) {
setMeasuredDimension(mRectWidth, mRectHeight * 4 + mRectGap * 3);
} else {
setMeasuredDimension(mRectWidth, mRectHeight * 3 + mRectGap * 2);
}
}
private int setHSVColor(float hue, float saturation, float value) {
float[] hsv = new float[3];
hsv[0] = Math.max(0, Math.min(359, hue));
hsv[1] = Math.max(0, Math.min(1, saturation));
hsv[2] = Math.max(0, Math.min(1, value));
return Color.HSVToColor(hsv);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
boolean inHue = mHueRect.contains((int) x, (int) y);
boolean inSaturation = mSaturationRect.contains((int) x, (int) y);
boolean inValue = mValueRect.contains((int) x, (int) y);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
if (inHue) {
float unit = x / mRectWidth;
mCurrentHSV[0] = Math.max(0, Math.min(unit * 360, 359));
updateCurrentColor();
} else if (inSaturation) {
mCurrentHSV[1] = Math.max(0, Math.min(x / mRectWidth, 1));
updateCurrentColor();
} else if (inValue) {
mCurrentHSV[2] = Math.max(0, Math.min(x / mRectWidth, 1));
updateCurrentColor();
}
break;
}
return true;
}
private void updateCurrentColor() {
mCurrentColor = Color.HSVToColor(mCurrentHSV);
if (mListener != null) {
mListener.onColorChanged(mCurrentColor, mCurrentHSV);
}
invalidate();
}
}