实列图:
源码:
ColorPickerView.java
package com.px.color; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ComposeShader; import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.PointF; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.Shader; import android.graphics.Shader.TileMode; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; public class ColorPickerView extends View { private Context mContext; private Paint mRightPaint; private int mHeight; private int mWidth; private int[] mRightColors; private int RIGHT_WIDTH; private int LEFT_WIDTH; private Bitmap mLeftBitmap; private Bitmap mLeftBitmap2; private Bitmap mRightBitmap; private Bitmap mRightBitmap2; private Paint mBitmapPaint; private final int SPLIT_WIDTH = 24; private boolean downInLeft = false; private boolean downInRight = false; private PointF mLeftSelectPoint; private PointF mRightSelectPoint; private OnColorChangedListener mChangedListener; private boolean mLeftMove = false; private boolean mRightMove = false; private float mLeftBitmapRadius; private Bitmap mGradualChangeBitmap; private float mRightBitmapHalfHeight; private float mRightBitmapQuarterWidth; private int mCallBackColor = Integer.MAX_VALUE; public ColorPickerView(Context context) { this(context, null); } public ColorPickerView(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; init(); } public void setOnColorChangedListenner(OnColorChangedListener listener) { mChangedListener = listener; } private void init() { mRightPaint = new Paint(); mRightPaint.setStyle(Paint.Style.FILL); mRightPaint.setStrokeWidth(1); mRightColors = new int[3]; mRightColors[0] = Color.WHITE; mRightColors[2] = Color.BLACK; mBitmapPaint = new Paint(); mLeftBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.reading__color_view__button); mLeftBitmap2 = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.reading__color_view__button_press); mLeftBitmapRadius = mLeftBitmap.getWidth() / 2; mLeftSelectPoint = new PointF(SPLIT_WIDTH, SPLIT_WIDTH); mRightBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.reading__color_view__saturation); mRightBitmap2 = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.reading__color_view__saturation_press); mRightSelectPoint = new PointF(SPLIT_WIDTH, SPLIT_WIDTH); mRightBitmapHalfHeight = mRightBitmap.getHeight() / 2; mRightBitmapQuarterWidth = mRightBitmap.getWidth() / 4; RIGHT_WIDTH = mRightBitmap.getWidth() / 2; } @Override protected void onDraw(Canvas canvas) { // 左边 canvas.drawBitmap(getGradual() , null , new Rect(SPLIT_WIDTH, SPLIT_WIDTH, LEFT_WIDTH + SPLIT_WIDTH, mHeight - SPLIT_WIDTH), mBitmapPaint); // 右边 mRightColors[1] = mRightPaint.getColor(); Shader rightShader = new LinearGradient(mWidth - SPLIT_WIDTH - RIGHT_WIDTH / 2, SPLIT_WIDTH, mWidth - SPLIT_WIDTH - RIGHT_WIDTH / 2, mHeight - SPLIT_WIDTH, mRightColors, null, Shader.TileMode.MIRROR); mRightPaint.setShader(rightShader); canvas.drawRect(new Rect(mWidth - SPLIT_WIDTH - RIGHT_WIDTH, SPLIT_WIDTH, mWidth - SPLIT_WIDTH, mHeight-SPLIT_WIDTH), mRightPaint); // 两个图标 if (mLeftMove) { canvas.drawBitmap(mLeftBitmap, mLeftSelectPoint.x - mLeftBitmapRadius, mLeftSelectPoint.y - mLeftBitmapRadius, mBitmapPaint); } else { canvas.drawBitmap(mLeftBitmap2, mLeftSelectPoint.x - mLeftBitmapRadius, mLeftSelectPoint.y - mLeftBitmapRadius, mBitmapPaint); } if (mRightMove) { canvas.drawBitmap(mRightBitmap, mWidth - SPLIT_WIDTH - RIGHT_WIDTH - mRightBitmapQuarterWidth, mRightSelectPoint.y - mRightBitmapHalfHeight, mBitmapPaint); } else { canvas.drawBitmap(mRightBitmap2, mWidth - SPLIT_WIDTH - RIGHT_WIDTH - mRightBitmapQuarterWidth, mRightSelectPoint.y - mRightBitmapHalfHeight, mBitmapPaint); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); if (widthMode == MeasureSpec.EXACTLY) { mWidth = width; } else { mWidth = 480; } if (heightMode == MeasureSpec.EXACTLY) { mHeight = height; } else { mHeight = 350; } LEFT_WIDTH = mWidth - SPLIT_WIDTH * 3 - RIGHT_WIDTH; setMeasuredDimension(mWidth, mHeight); } @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); float y = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: downInLeft = inLeftPanel(x, y); downInRight = inRightPanel(x, y); if (downInLeft) { mLeftMove = true; proofLeft(x, y); mRightPaint.setColor(getLeftColor(mLeftSelectPoint.x-SPLIT_WIDTH, mLeftSelectPoint.y-SPLIT_WIDTH)); } else if (downInRight) { mRightMove = true; proofRight(x, y); } invalidate(); int rightColor = getRightColor(mRightSelectPoint.y - SPLIT_WIDTH); if (mCallBackColor == Integer.MAX_VALUE || mCallBackColor != rightColor) { mCallBackColor = rightColor; } else { break; } if (mChangedListener != null) { mChangedListener.onColorChanged(mCallBackColor, mRightPaint.getColor(), (mRightSelectPoint.y - SPLIT_WIDTH) / (mHeight - 2 * SPLIT_WIDTH)); } break; case MotionEvent.ACTION_UP: if (downInLeft) { downInLeft = false; } else if (downInRight) { downInRight = false; } mLeftMove = false; mRightMove = false; invalidate(); if (mChangedListener != null) { mChangedListener.onColorChanged(getRightColor(mRightSelectPoint.y - SPLIT_WIDTH), mRightPaint.getColor(), (mRightSelectPoint.y - SPLIT_WIDTH) / (mHeight - 2 * SPLIT_WIDTH)); } } return true; } @Override protected void onDetachedFromWindow() { if (mGradualChangeBitmap != null && mGradualChangeBitmap.isRecycled() == false) { mGradualChangeBitmap.recycle(); } if (mLeftBitmap != null && mLeftBitmap.isRecycled() == false) { mLeftBitmap.recycle(); } if (mLeftBitmap2 != null && mLeftBitmap2.isRecycled() == false) { mLeftBitmap2.recycle(); } if (mRightBitmap != null && mRightBitmap.isRecycled() == false) { mRightBitmap.recycle(); } if (mRightBitmap2 != null && mRightBitmap2.isRecycled() == false) { mRightBitmap2.recycle(); } super.onDetachedFromWindow(); } private Bitmap getGradual() { if (mGradualChangeBitmap == null) { Paint leftPaint = new Paint(); leftPaint.setStrokeWidth(1); mGradualChangeBitmap = Bitmap.createBitmap(LEFT_WIDTH, mHeight - 2 * SPLIT_WIDTH, Config.RGB_565); Canvas canvas = new Canvas(mGradualChangeBitmap); int bitmapWidth = mGradualChangeBitmap.getWidth(); LEFT_WIDTH = bitmapWidth; int bitmapHeight = mGradualChangeBitmap.getHeight(); int[] leftColors = new int[] {Color.RED, Color.YELLOW, Color.GREEN, Color.CYAN, Color.BLUE, Color.MAGENTA}; Shader leftShader = new LinearGradient(0, bitmapHeight / 2, bitmapWidth, bitmapHeight / 2, leftColors, null, TileMode.REPEAT); LinearGradient shadowShader = new LinearGradient(bitmapWidth / 2, 0, bitmapWidth / 2, bitmapHeight, Color.WHITE, Color.BLACK, Shader.TileMode.CLAMP); ComposeShader shader = new ComposeShader(leftShader, shadowShader, PorterDuff.Mode.SCREEN); leftPaint.setShader(shader); canvas.drawRect(0, 0, bitmapWidth, bitmapHeight, leftPaint); } return mGradualChangeBitmap; } private boolean inLeftPanel(float x, float y) { if ( 0 < x && x < SPLIT_WIDTH + LEFT_WIDTH + SPLIT_WIDTH / 2 && 0 < y && y < mWidth) { return true; } else { return false; } } private boolean inRightPanel(float x, float y) { if (mWidth - SPLIT_WIDTH - RIGHT_WIDTH - SPLIT_WIDTH / 2 < x && x < mWidth && 0 < y && y < mHeight) { return true; } else { return false; } } // 校正xy private void proofLeft(float x, float y) { if (x < SPLIT_WIDTH) { mLeftSelectPoint.x = SPLIT_WIDTH; } else if (x > (SPLIT_WIDTH + LEFT_WIDTH)) { mLeftSelectPoint.x = SPLIT_WIDTH + LEFT_WIDTH; } else { mLeftSelectPoint.x = x; } if (y < SPLIT_WIDTH) { mLeftSelectPoint.y = SPLIT_WIDTH; } else if (y > (mHeight - SPLIT_WIDTH)) { mLeftSelectPoint.y = mHeight - SPLIT_WIDTH; } else { mLeftSelectPoint.y = y; } } private void proofRight(float x, float y) { if (x < SPLIT_WIDTH) { mRightSelectPoint.x = SPLIT_WIDTH; } else if (x > (SPLIT_WIDTH + LEFT_WIDTH)) { mRightSelectPoint.x = SPLIT_WIDTH + LEFT_WIDTH; } else { mRightSelectPoint.x = x; } if (y < SPLIT_WIDTH) { mRightSelectPoint.y = SPLIT_WIDTH; } else if (y > (mHeight - SPLIT_WIDTH)) { mRightSelectPoint.y = mHeight - SPLIT_WIDTH; } else { mRightSelectPoint.y = y; } } private int getLeftColor(float x, float y) { Bitmap temp = getGradual(); // 为了防止越界 int intX = (int) x; int intY = (int) y; if (intX >= temp.getWidth()) { intX = temp.getWidth() - 1; } if (intY >= temp.getHeight()) { intY = temp.getHeight() - 1; } return temp.getPixel(intX, intY); } private int getRightColor(float y) { int a, r, g, b, so, dst; float p; float rightHalfHeight = (mHeight - (float)SPLIT_WIDTH * 2) / 2; if (y < rightHalfHeight) { so = mRightColors[0]; dst = mRightColors[1]; p = y / rightHalfHeight; } else { so = mRightColors[1]; dst = mRightColors[2]; p = (y - rightHalfHeight) / rightHalfHeight; } a = ave(Color.alpha(so), Color.alpha(dst), p); r = ave(Color.red(so), Color.red(dst), p); g = ave(Color.green(so), Color.green(dst), p); b = ave(Color.blue(so), Color.blue(dst), p); return Color.argb(a, r, g, b); } private int ave(int s, int d, float p) { return s + Math.round(p * (d - s)); } // ### 内部类 ### public interface OnColorChangedListener { void onColorChanged(int color, int originalColor, float saturation); } }
测试代码:
ColorPickerActivity.java
package com.px.color; import com.px.color.ColorPickerView.OnColorChangedListener; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.widget.TextView; public class ColorPickerActivity extends Activity{ /** Called when the activity is first created. */ TextView tv = null; ColorPickerView cpv = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); cpv = (ColorPickerView)findViewById(R.id.colorpicker); cpv.setOnColorChangedListenner(colorChangedListener); tv = (TextView)findViewById(R.id.tv); } OnColorChangedListener colorChangedListener = new OnColorChangedListener(){ @Override public void onColorChanged(int color, int originalColor, float saturation) { Log.v("ColorPickerActivity", "color = " + color + ", " + "originalColor = " + originalColor); tv.setBackgroundColor(color); } }; }