拾色器不按预期工作

时间:2014-01-15 05:49:18

标签: android colors color-picker

以下是颜色选择器代码:

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;


public class ColorPicker extends AlertDialog {

        private static final int PADDING_DP = 20;

        private static final int CONTROL_SPACING_DP = 20;
        private static final int SELECTED_COLOR_HEIGHT_DP = 50;
        private static final int BORDER_DP = 1;
        private static final int BORDER_COLOR = Color.BLACK;

        private final OnColorSelectedListener listener;
        private int selectedColor;

        public interface OnColorSelectedListener {
                /**
                 * @param color The color code selected, or null if no color. No color is only
                 * possible if {@link HSVColorPickerDialog#setNoColorButton(int) setNoColorButton()}
                 * has been called on the dialog before showing it
                 */
                public void colorSelected( Integer color );
        }

        public ColorPicker(Context context, int initialColor, final OnColorSelectedListener listener) {
                super(context);
                this.selectedColor = initialColor;
                this.listener = listener;

                colorWheel = new HSVColorWheel( context );
                valueSlider = new HSVValueSlider( context );
                int padding = (int) (context.getResources().getDisplayMetrics().density * PADDING_DP);
                int borderSize = (int) (context.getResources().getDisplayMetrics().density * BORDER_DP);
                RelativeLayout layout = new RelativeLayout( context );

                RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT );
                lp.bottomMargin = (int) (context.getResources().getDisplayMetrics().density * CONTROL_SPACING_DP);
                colorWheel.setListener( new OnColorSelectedListener() {
                        public void colorSelected(Integer color) {
                                valueSlider.setColor( color, true );
                        }
                } );
                colorWheel.setColor( initialColor );
                colorWheel.setId( 1 );
                layout.addView( colorWheel, lp );

                int selectedColorHeight = (int) (context.getResources().getDisplayMetrics().density * SELECTED_COLOR_HEIGHT_DP);

                FrameLayout valueSliderBorder = new FrameLayout( context );
                valueSliderBorder.setBackgroundColor( BORDER_COLOR );
                valueSliderBorder.setPadding( borderSize, borderSize, borderSize, borderSize );
                valueSliderBorder.setId( 2 );
                lp = new RelativeLayout.LayoutParams( LayoutParams.MATCH_PARENT, selectedColorHeight + 2 * borderSize );
                lp.bottomMargin = (int) (context.getResources().getDisplayMetrics().density * CONTROL_SPACING_DP);
                lp.addRule( RelativeLayout.BELOW, 1 );
                layout.addView( valueSliderBorder, lp );

                valueSlider.setColor( initialColor, false );
                valueSlider.setListener( new OnColorSelectedListener() {
                        @Override
                        public void colorSelected(Integer color) {
                                selectedColor = color;
                                selectedColorView.setBackgroundColor( color );
                        }
                });
                valueSliderBorder.addView( valueSlider );

                FrameLayout selectedColorborder = new FrameLayout( context );
                selectedColorborder.setBackgroundColor( BORDER_COLOR );
                lp = new RelativeLayout.LayoutParams( LayoutParams.MATCH_PARENT, selectedColorHeight + 2 * borderSize );
                selectedColorborder.setPadding( borderSize, borderSize, borderSize, borderSize );
                lp.addRule( RelativeLayout.BELOW, 2 );
                layout.addView( selectedColorborder, lp );

                selectedColorView = new View( context );
                selectedColorView.setBackgroundColor( selectedColor );
                selectedColorborder.addView( selectedColorView );

                setButton( BUTTON_NEGATIVE, context.getString( android.R.string.cancel ), clickListener );
                setButton( BUTTON_POSITIVE, context.getString( android.R.string.ok ), clickListener );

                setView( layout, padding, padding, padding, padding );
        }

        private OnClickListener clickListener = new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                        switch ( which ) {
                        case BUTTON_NEGATIVE:
                                dialog.dismiss();
                                break;
                        case BUTTON_NEUTRAL:
                                dialog.dismiss();
                                listener.colorSelected( -1 );
                                break;
                        case BUTTON_POSITIVE:
                                listener.colorSelected( selectedColor );
                                break;
                        }
                }
        };

        private HSVColorWheel colorWheel;
        private HSVValueSlider valueSlider;

        private View selectedColorView;

        /**
         * Adds a button to the dialog that allows a user to select "No color",
         * which will call the listener's {@link OnColorSelectedListener#colorSelected(Integer) colorSelected(Integer)} callback
         * with null as its parameter  
         * @param res A string resource with the text to be used on this button
         */
        public void setNoColorButton( int res ) {
                setButton( BUTTON_NEUTRAL, getContext().getString( res ), clickListener ); 
        }

        private static class HSVColorWheel  extends View {

                private static final float SCALE = 2f;
                private static final float FADE_OUT_FRACTION = 0.03f;

                private static final int POINTER_LINE_WIDTH_DP = 2;
                private static final int POINTER_LENGTH_DP = 10;

                private final Context context;

                private OnColorSelectedListener listener;
                public HSVColorWheel(Context context, AttributeSet attrs, int defStyle) {
                        super(context, attrs, defStyle);
                        this.context = context;
                        init();
                }

                public HSVColorWheel(Context context, AttributeSet attrs) {
                        super(context, attrs);
                        this.context = context;
                        init();
                }

                public HSVColorWheel(Context context) {
                        super(context);
                        this.context = context;
                        init();
                }

                private int scale;
                private int pointerLength;
                private int innerPadding;
                private Paint pointerPaint = new Paint();
                private void init() {
                        float density = context.getResources().getDisplayMetrics().density;
                        scale = (int) (density * SCALE);
                        pointerLength = (int) (density * POINTER_LENGTH_DP );
                        pointerPaint.setStrokeWidth(  (int) (density * POINTER_LINE_WIDTH_DP ) );
                        innerPadding = pointerLength / 2;
                }

                public void setListener( OnColorSelectedListener listener ) {
                        this.listener = listener;
                }

                float[] colorHsv = { 0f, 0f, 1f };
                public void setColor( int color ) {
                        Color.colorToHSV(color, colorHsv);
                        invalidate();
                }

                @Override
                protected void onDraw(Canvas canvas) {
                        if ( bitmap != null ) {
                                canvas.drawBitmap(bitmap, null, rect, null);
                                float hueInPiInterval = colorHsv[0] / 180f * (float)Math.PI;

                                selectedPoint.x = rect.left + (int) (-FloatMath.cos( hueInPiInterval ) * colorHsv[1] * innerCircleRadius + fullCircleRadius);
                                selectedPoint.y = rect.top + (int) (-FloatMath.sin( hueInPiInterval ) * colorHsv[1] * innerCircleRadius + fullCircleRadius);

                                canvas.drawLine( selectedPoint.x - pointerLength, selectedPoint.y, selectedPoint.x + pointerLength, selectedPoint.y, pointerPaint );
                                canvas.drawLine( selectedPoint.x, selectedPoint.y - pointerLength, selectedPoint.x, selectedPoint.y + pointerLength, pointerPaint );
                        }
                }

                private Rect rect;
                private Bitmap bitmap;

                private int[] pixels;
                private float innerCircleRadius;
                private float fullCircleRadius;

                private int scaledWidth;
                private int scaledHeight;
                private int[] scaledPixels;

                private float scaledInnerCircleRadius;
                private float scaledFullCircleRadius;
                private float scaledFadeOutSize;

                private Point selectedPoint = new Point();

                @Override
                protected void onSizeChanged(int w, int h, int oldw, int oldh) {
                        super.onSizeChanged(w, h, oldw, oldh);

                        rect = new Rect( innerPadding, innerPadding, w - innerPadding, h - innerPadding );
                        bitmap = Bitmap.createBitmap( w - 2 * innerPadding, h - 2 * innerPadding, Config.ARGB_8888 );

                        fullCircleRadius = Math.min( rect.width(), rect.height() ) / 2;
                        innerCircleRadius = fullCircleRadius * ( 1 - FADE_OUT_FRACTION );

                        scaledWidth = rect.width() / scale;
                        scaledHeight = rect.height() / scale;
                        scaledFullCircleRadius = Math.min( scaledWidth, scaledHeight ) / 2;
                        scaledInnerCircleRadius = scaledFullCircleRadius * ( 1 - FADE_OUT_FRACTION );
                        scaledFadeOutSize = scaledFullCircleRadius - scaledInnerCircleRadius;
                        scaledPixels = new int[ scaledWidth * scaledHeight ];
                        pixels = new int[ rect.width() * rect.height() ];

                        createBitmap();
                }

                private void createBitmap() {
                        int w = rect.width();
                        int h = rect.height();

                        float[] hsv = new float[] { 0f, 0f, 1f };
                        int alpha = 255;

                        int x = (int) -scaledFullCircleRadius, y = (int) -scaledFullCircleRadius;
                        for ( int i = 0; i < scaledPixels.length; i++ ) {
                                if ( i % scaledWidth == 0 ) {
                                        x = (int) -scaledFullCircleRadius;
                                        y++;
                                } else {
                                        x++;
                                }

                                double centerDist = Math.sqrt( x*x + y*y );
                                if ( centerDist <= scaledFullCircleRadius ) {
                                        hsv[ 0 ] = (float) (Math.atan2( y, x ) / Math.PI * 180f) + 180;
                                        hsv[ 1 ] = (float) (centerDist / scaledInnerCircleRadius);
                                        if ( centerDist <= scaledInnerCircleRadius ) {
                                                alpha = 255;
                                        } else {
                                                alpha = 255 - (int) ((centerDist - scaledInnerCircleRadius) / scaledFadeOutSize * 255);
                                        }
                                        scaledPixels[ i ] = Color.HSVToColor( alpha, hsv );
                                } else {
                                        scaledPixels[ i ] = 0x00000000;
                                }
                        }

                        int scaledX, scaledY;
                        for( x = 0; x < w; x++ ) {
                                scaledX = x / scale;
                                if ( scaledX >= scaledWidth ) scaledX = scaledWidth - 1;
                                for ( y = 0; y < h; y++ ) {
                                        scaledY = y / scale;
                                        if ( scaledY >= scaledHeight ) scaledY = scaledHeight - 1;
                                        pixels[ x * h + y ] = scaledPixels[ scaledX * scaledHeight + scaledY ];
                                }
                        }

                        bitmap.setPixels( pixels, 0, w, 0, 0, w, h );

                        invalidate();
                }

                @Override
                protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
                        int maxWidth = MeasureSpec.getSize( widthMeasureSpec );
                        int maxHeight = MeasureSpec.getSize( heightMeasureSpec );

                        int width, height;
                        /*
                         * Make the view quadratic, with height and width equal and as large as possible
                         */
                        width = height = Math.min( maxWidth, maxHeight );

                        setMeasuredDimension( width, height );
                }

                public int getColorForPoint( int x, int y, float[] hsv ) {
                        x -= fullCircleRadius;
                        y -= fullCircleRadius;
                        double centerDist = Math.sqrt( x*x + y*y );
                        hsv[ 0 ] = (float) (Math.atan2( y, x ) / Math.PI * 180f) + 180;
                        hsv[ 1 ] = Math.max( 0f, Math.min( 1f, (float) (centerDist / innerCircleRadius) ) );
                        return Color.HSVToColor( hsv );
                }

                @Override
                public boolean onTouchEvent(MotionEvent event) {
                        int action = event.getActionMasked();
                        switch ( action ) {
                        case MotionEvent.ACTION_DOWN:
                        case MotionEvent.ACTION_MOVE:
                                if ( listener != null ) {
                                        listener.colorSelected( getColorForPoint( (int)event.getX(), (int)event.getY(), colorHsv ) );
                                }
                                invalidate();
                                return true;
                        }
                        return super.onTouchEvent(event);
                }

        }

        private static class HSVValueSlider extends View {

                public HSVValueSlider(Context context, AttributeSet attrs, int defStyle) {
                        super(context, attrs, defStyle);
                }

                public HSVValueSlider(Context context, AttributeSet attrs) {
                        super(context, attrs);
                }

                public HSVValueSlider(Context context) {
                        super(context);
                }

                private OnColorSelectedListener listener;
                public void setListener( OnColorSelectedListener listener ) {
                        this.listener = listener;
                }

                float[] colorHsv = { 0f, 0f, 1f };
                public void setColor( int color, boolean keepValue ) {
                        float oldValue = colorHsv[2];
                        Color.colorToHSV(color, colorHsv);
                        if ( keepValue ) {
                                colorHsv[2] = oldValue;
                        }
                        if ( listener != null ) {
                                listener.colorSelected( Color.HSVToColor( colorHsv ) );
                        }

                        createBitmap();
                }

                @Override
                protected void onDraw(Canvas canvas) {
                        if ( bitmap != null ) {
                                canvas.drawBitmap(bitmap, srcRect, dstRect, null);
                        }
                }
                private Rect srcRect;
                private Rect dstRect;
                private Bitmap bitmap;
                private int[] pixels;

                @Override
                protected void onSizeChanged(int w, int h, int oldw, int oldh) {
                        super.onSizeChanged(w, h, oldw, oldh);

                        srcRect = new Rect( 0, 0, w, 1 );
                        dstRect = new Rect( 0, 0, w, h );
                        bitmap = Bitmap.createBitmap( w, 1, Config.ARGB_8888 );
                        pixels = new int[ w ];

                        createBitmap();
                }

                private void createBitmap() {
                        if ( bitmap == null ) {
                                return;
                        }
                        int w = getWidth();

                        float[] hsv = new float[] { colorHsv[0], colorHsv[1], 1f };

                        int selectedX = (int) (colorHsv[ 2 ] * w);

                        float value = 0;
                        float valueStep = 1f / w;
                        for( int x = 0; x < w; x++ ) {
                                value += valueStep;
                                if ( x >= selectedX - 1 && x <= selectedX + 1 ) {
                                        int intVal = 0xFF - (int)( value * 0xFF );
                                        int color = intVal * 0x010101 + 0xFF000000;
                                        pixels[x] = color;
                                } else {
                                        hsv[2] = value;
                                        pixels[x] = Color.HSVToColor( hsv );
                                }
                        }

                        bitmap.setPixels( pixels, 0, w, 0, 0, w, 1 );

                        invalidate();
                }

                @Override
                public boolean onTouchEvent(MotionEvent event) {
                        int action = event.getActionMasked();
                        switch ( action ) {
                        case MotionEvent.ACTION_DOWN:
                        case MotionEvent.ACTION_MOVE:
                                int x = Math.max( 0, Math.min( bitmap.getWidth() - 1, (int)event.getX() ) );
                                float value = x / (float)bitmap.getWidth();
                                if ( colorHsv[2] != value ) {
                                        colorHsv[2] = value;
                                        if ( listener != null ) {
                                                listener.colorSelected( Color.HSVToColor( colorHsv ) );
                                        }
                                        createBitmap();
                                        invalidate();
                                }
                                return true;
                        }
                        return super.onTouchEvent(event);
                }

        }

}

以下是我在主要活动中使用它的方式......

ColorPicker cp = new ColorPicker(this, 0, new ColorPicker.OnColorSelectedListener() {

            @Override
            public void colorSelected(Integer color) {
                System.out.println(color.toString());
            }
        });
        cp.setTitle( "Pick a color" );
        cp.show();

这就是我得到的:

enter image description here

问题是,我只能改变黑色的阴影,当我将光标更改为指向色轮上的另一种颜色时,它会保持黑色。为什么会这样?

编辑:我发现了根本问题!即使我更改了colorWheel,它也只会返回黑色。为什么呢?

1 个答案:

答案 0 :(得分:2)

此问题的快速解决方案是将初始颜色设置为0xffffff。这个颜色选择器中有一个错误。

您可能想尝试使用HSV颜色模型的颜色选择器。它可以在GitHub上找到:https://github.com/chiralcode/Android-Color-Picker