スポンサーリンク

Androidで使える、ColorPickerDialogをスマホのサイズに自動で合わせるようにしたよ

colorfulスマホアプリ
スポンサーリンク

スマホアプリ、黙々と開発中

地道にAndroid用アプリのプログラムを勉強していますので、なかなかブログを更新するようなネタがありませんでした、すっかりご無沙汰してしまいました。
そんな中で、色設定の機能が必要だったので調べてみたところ、ColorPickerDialogを自作して公開されている素敵な方がいらっしゃいました。
Android ColorPickerDialog を作った-Y.A.M の 雑記帳
すげー、世の中助け合いですよね、もしかして女神様なのでは!?なんて思いながらさっそく使わせていただきました。超便利。

あ、サイズが固定されてる・・・。

ただ、このコードは1つ問題があって、表示のサイズが固定されているんですよ。だから、スマホの解像度によって端っこに寄ってしまう。これはまずいので、スマホのサイズに合わせて真ん中に表示されるように修正しました。
以下のコードで大丈夫だと思います、ぜひご参考に。

import android.app.Dialog;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.os.Bundle;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;


public class ColorPickerDialog extends Dialog {

    public interface OnColorChangedListener {
        void colorChanged(int color);
    }

    private OnColorChangedListener mListener;
    private int mInitialColor;

    private static class ColorPickerView extends View {

        private Paint mPaint, mPaintC;
        private Paint mOKPaint;
        private final int[] mColors;
        private int[] mChroma;
        private OnColorChangedListener mListener;
        private Shader sg, lg;
        private int selectColor;
        private float selectHue = 0;

        ColorPickerView(Context c, OnColorChangedListener l, int color) {
            super(c);
            mListener = l;
            selectColor = color;
            selectHue = getHue(selectColor);
            mColors = new int[] {
                    0xFFFF0000, 0xFFFF00FF, 0xFF0000FF, 0xFF00FFFF, 0xFF00FF00,
                    0xFFFFFF00, 0xFFFF0000
            };

            mChroma = new int[] {
                    0xFF000000, 0xFF888888, 0xFFFFFFFF
            };
/*ここからスマホの表示エリアのサイズを取得*/
            WindowManager manager = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
            Display display = manager.getDefaultDisplay();
            Point p = new Point();
            display.getSize(p);
/*ここまで*/
/*表示エリアのサイズを元に表示サイズを設定*/
            CENTER_X = p.x/2;
            CENTER_Y = p.x/2;
            CENTER_RADIUS = CENTER_Y*20/100;
            OK_X0 = - CENTER_X/2*0.7f;
            OK_X1 =   CENTER_X/2*0.7f;
            OK_Y0 = (float) (CENTER_X * 1.2);
            OK_Y1 = (float) (CENTER_X * 1.5);

            sg = new SweepGradient(0, 0, mColors, null);
            lg = new LinearGradient(OK_X0, 0, OK_X1, 0, mChroma, null, Shader.TileMode.CLAMP);

            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setShader(sg);
            mPaint.setStrokeWidth(CENTER_RADIUS);

            mPaintC = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPaintC.setStyle(Paint.Style.FILL);
            mPaintC.setShader(lg);
            mPaintC.setStrokeWidth(CENTER_X*2/100);

            mOKPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mOKPaint.setStyle(Paint.Style.FILL);
            mOKPaint.setColor(selectColor);
            mOKPaint.setStrokeWidth(CENTER_X*5/100);
        }

        private boolean mTrackingOK;
        private boolean mHighlightOK;
/*固定設定を解除*/
        int CENTER_X;
        int CENTER_Y;
        //private static final int CENTER_X = 300;
        //private static final int CENTER_Y = 300;
        /*private static final*/ int CENTER_RADIUS;
        /*private static final*/  float OK_X0;
        /*private static final*/ float OK_X1;
        /*private static final*/  float OK_Y0;
        /*private static final*/ float OK_Y1;

        private void drawSVRegion(Canvas canvas) {
            final float RESOLUTION = (float)0.01;

            for(float y = 0; y < 1; y += RESOLUTION) {
                mChroma = new int[10];

                int i = 0;
                for(float x = 0; i < 10; x += 0.1, i+=1) {
                    mChroma[i] = setHSVColor(selectHue, x, y);
                }
                lg = new LinearGradient(OK_X0, 0, OK_X1, 0, mChroma, null, Shader.TileMode.CLAMP);
                mPaintC.setShader(lg);

                //canvas.drawRect(OK_X0, OK_X0 + (CENTER_X * y), OK_X1, OK_X0 + (float)(CENTER_X * (y)), mPaintC);
                /*ここの0.7は上の0.7を変えた場合は数字揃えてね*/
                canvas.drawLine(OK_X0, OK_X0 + (CENTER_X*0.7f * y), OK_X1, OK_X0 + (CENTER_X*0.7f * y), mPaintC);
            }
        }

        @Override
        protected void onDraw(Canvas canvas) {
            float r =(CENTER_X - mPaint.getStrokeWidth()) * 0.9f;

            canvas.translate(CENTER_X, CENTER_Y);
            canvas.drawOval(new RectF(-r, -r, r, r), mPaint);

            drawSVRegion(canvas);

            canvas.drawRoundRect(new RectF(OK_X0, OK_Y0, OK_X1, OK_Y1), 5, 5, mOKPaint);

            Paint textPaint = new Paint();
            textPaint.setColor(Color.WHITE);
            textPaint.setTextSize(CENTER_X*0.1f);
            textPaint.setAntiAlias(true);
           /*微調整が必要*/
            canvas.drawText("OK", -14*CENTER_X/100, (float) (CENTER_X * 1.4) + 2, textPaint);

            if (mTrackingOK) {
                int c = mOKPaint.getColor();
                mOKPaint.setStyle(Paint.Style.STROKE);

                if (mHighlightOK)
                    mOKPaint.setAlpha(0xFF);
                else
                    mOKPaint.setAlpha(0x80);

                float padding = 5;
                //canvas.drawCircle(0, 0, CENTER_RADIUS + mOKPaint.getStrokeWidth(), mOKPaint);
                canvas.drawRoundRect(new RectF(OK_X0 - padding, OK_Y0 - padding, OK_X1 + padding, OK_Y1 + padding), 5, 5, mOKPaint);
                mOKPaint.setStyle(Paint.Style.FILL);
                mOKPaint.setColor(c);
            }
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            setMeasuredDimension(CENTER_X * 2, (int)(CENTER_Y * 2.8));
        }

        private int floatToByte(float x) {
            int n = java.lang.Math.round(x);
            return n;
        }

        private int pinToByte(int n) {
            if (n < 0)
                n = 0;
            else if (n > 255)
                n = 255;
            return n;
        }

        private float getHue(int color) {
            float hsv[] = new float[3];
            Color.colorToHSV(color, hsv);
            return hsv[0];
        }

        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);
        }

        private int rotateColor(int color, float rad) {
            float deg = rad * 180 / PI;
            int r = Color.red(color);
            int g = Color.green(color);
            int b = Color.blue(color);

            ColorMatrix cm  = new ColorMatrix();
            ColorMatrix tmp = new ColorMatrix();

            cm.setRGB2YUV();
            tmp.setRotate(0, deg);
            cm.postConcat(tmp);
            tmp.setYUV2RGB();
            cm.postConcat(tmp);

            final float[] a = cm.getArray();

            int ir = floatToByte(a[0] * r +  a[1] * g +  a[2] * b);
            int ig = floatToByte(a[5] * r +  a[6] * g +  a[7] * b);
            int ib = floatToByte(a[10] * r + a[11] * g + a[12] * b);

            return Color.argb(Color.alpha(color), pinToByte(ir), pinToByte(ig), pinToByte(ib));
        }

        private int setHSVColor(float hue, float saturation, float value) {
            float[] hsv = new float[3];
            if(hue >= 360)
                hue = 359;
            else if(hue < 0)
                hue = 0;

            if(saturation > 1)
                saturation = 1;
            else if(saturation < 0)
                saturation = 0;

            if(value > 1)
                value = 1;
            else if(value < 0)
                value = 0;

            hsv[0] = hue;
            hsv[1] = saturation;
            hsv[2] = value;

            return Color.HSVToColor(hsv);
        }

        private static final float PI = 3.1415927f;

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            float x = event.getX() - CENTER_X;
            float y = event.getY() - CENTER_Y;
            float r = (float)(java.lang.Math.sqrt(x*x + y*y));
            boolean inOK = false;
            boolean inOval = false;
            boolean inRect = false;

            if(r <= CENTER_X) {
                if(r > (CENTER_X - CENTER_RADIUS)*0.9)
                    inOval = true;
                else if(x >= OK_X0 && x < OK_X1 && y >= OK_X0 && y < OK_X1)
                    inRect = true;
            }
            else if(x >= OK_X0 && x < OK_X1 && y >= OK_Y0 && y < OK_Y1){
                inOK = true;
            }

            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    mTrackingOK = inOK;
                    if (inOK) {
                        mHighlightOK = true;
                        invalidate();
                        break;
                    }
                case MotionEvent.ACTION_MOVE:
                    if (mTrackingOK) {
                        if (mHighlightOK != inOK) {
                            mHighlightOK = inOK;
                            invalidate();
                        }
                    }
                    else if(inOval) {
                        float angle = (float)java.lang.Math.atan2(y, x);
                        // need to turn angle [-PI ... PI] into unit [0....1]
                        float unit = angle/(2*PI);
                        if (unit < 0) {
                            unit += 1;
                        }
                        selectColor = interpColor(mColors, unit);
                        mOKPaint.setColor(selectColor);
                        //mChroma[1] = selectColor;
                        selectHue = getHue(selectColor);
                        //lg = new LinearGradient(OK_X0, 0, OK_X1, 0, mChroma, null, Shader.TileMode.CLAMP);
                        //mPaintC.setShader(lg);
                        invalidate();
                    }
                    else if(inRect){
                        int selectColor2 = setHSVColor(selectHue, (x - OK_X0)/CENTER_X/0.7f, (y - OK_X0)/CENTER_Y/0.7f);
                        selectColor = selectColor2;
                        mOKPaint.setColor(selectColor);
                        invalidate();
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    if (mTrackingOK) {
                        if (inOK) {
                            mListener.colorChanged(mOKPaint.getColor());
                        }
                        mTrackingOK = false;    // so we draw w/o halo
                        invalidate();
                    }
                    break;
            }
            return true;
        }
    }


    public ColorPickerDialog(Context context, OnColorChangedListener listener, int initialColor) {
        super(context);
        mListener = listener;
        mInitialColor = initialColor;
    }

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        OnColorChangedListener l = new OnColorChangedListener() {
            public void colorChanged(int color) {
                mListener.colorChanged(color);
                dismiss();
            }
        };

        ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        setContentView(new ColorPickerView(getContext(), l, mInitialColor), lp);
        setTitle("- Color -");
    }

}

ちなみに、うまく行った場合の見栄えはこんな感じ。
Screenshot_ColorPickerDialog

これを使ってアプリが完成しました!

このダイアログを応用して、アプリが完成しました!

初心者でもAndroidのカラーコーディネート用アプリが作れた
初めてのアンドロイドアプリ、何とか完成 下のこの記事からはや2か月、ようやく初めてのスマホアプリを世の中に出すことができました。思ってたよりも苦しみました。もっと簡単にさくっとできる予定だっ...
モノクロ画像を作るスマホアプリを作ったよ
オシャレ画像加工アプリ第3弾 第1弾のRainbowgram、第2弾のGradientgramに続いて第3弾の画像加工用Androidアプリを作りました。 名前は、Mono...
スマホアプリ
スポンサーリンク
スポンサーリンク
良いなと思ったら、シェアしてください
このブログをフォローする
Findelight

コメント