android 自定义View【2】对话框取色&色盘取色的实现

来源:互联网 发布:企业建站优化方案 编辑:程序博客网 时间:2024/05/16 09:43
android 自定义View【2】对话框取色&色盘取色的实现
   上一篇文章基本介绍了android自定义view的流程:继承view,复写view的一些方法。实现简单的自定义view。这篇文章主要介绍的是系统对话框取色功能,然后顺便介绍升级版,色盘取色【类似于ps中的吸管,对图片点击相应位置,获取那个位置的颜色】。

一、概述:通过该例子了解以下内容:

1、进一步了解android 自定义view。
2、知道如何获取图片上的颜色值。
3、监听屏幕touch,实现移动的时候自动取色。【onDraw与onMeasure 的配合】
4、了解定义接口和匿名内部类调用。



二、介绍运用api demo 中的ColorPickerDialog 步骤:实现对话框取色。

1、新建安卓工程、命名为GetColorDemo
2、将\android-sdks\samples\android-13\ApiDemos\src\com\example\android\apis\graphics目录下的 ColorPickerDialog.java 文件 拷贝到工程。ColorPickerDialog代码如下: 

<span style="font-size:18px;">/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package demo.dim.getcolordemo;import android.os.Bundle;import android.app.Dialog;import android.content.Context;import android.graphics.*;import android.util.Log;import android.view.MotionEvent;import android.view.View;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;        private Paint mCenterPaint;        private final int[] mColors;        private OnColorChangedListener mListener;        private String TAG="ColorPicker-->>";        ColorPickerView(Context c, OnColorChangedListener l, int color) {            super(c);            mListener = l;            mColors = new int[] {                0xFFFF0000, 0xFFFF00FF, 0xFF0000FF, 0xFF00FFFF, 0xFF00FF00,                0xFFFFFF00, 0xFFFF0000            };                         //颜色渲染            Shader s = new SweepGradient(0, 0, mColors, null);            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);            mPaint.setShader(s);            mPaint.setStyle(Paint.Style.STROKE);            mPaint.setStrokeWidth(32);            mCenterPaint = new Paint(Paint.ANTI_ALIAS_FLAG);            mCenterPaint.setColor(color);            mCenterPaint.setStrokeWidth(5);        }        private boolean mTrackingCenter;        private boolean mHighlightCenter;        @Override        protected void onDraw(Canvas canvas) {            float r = CENTER_X - mPaint.getStrokeWidth()*0.5f;            canvas.translate(CENTER_X, CENTER_X);            canvas.drawOval(new RectF(-r, -r, r, r), mPaint);            canvas.drawCircle(0, 0, CENTER_RADIUS, mCenterPaint);            if (mTrackingCenter) {                int c = mCenterPaint.getColor();                mCenterPaint.setStyle(Paint.Style.STROKE);                if (mHighlightCenter) {                    mCenterPaint.setAlpha(0xFF);                } else {                    mCenterPaint.setAlpha(0x80);                }                canvas.drawCircle(0, 0,                                  CENTER_RADIUS + mCenterPaint.getStrokeWidth(),                                  mCenterPaint);                mCenterPaint.setStyle(Paint.Style.FILL);                mCenterPaint.setColor(c);            }        }        @Override        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        //只有在 0 0 200 200 范围内。定义视图大小。        //就是200*200的正方形范围内。             setMeasuredDimension(CENTER_X*2, CENTER_Y*2);        }        private static final int CENTER_X = 100;        private static final int CENTER_Y = 100;        private static final int CENTER_RADIUS = 32;        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 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];                                   /**             * 四舍五入              *         private int ave(int s, int d, float p) {            return s + java.lang.Math.round(p * (d - s));        }             */            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 / 3.1415927f;            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 static final float PI = 3.1415926f;        @Override        public boolean onTouchEvent(MotionEvent event) {        //setMeasuredDimension(CENTER_X*2, CENTER_Y*2);        //这决定了 event.getX() <=200;event.getY()<=200            float x = event.getX() - CENTER_X;            float y = event.getY() - CENTER_Y;                        Log.i(TAG, "x="+ event.getX()+"  y="+event.getY());            //如果半径小于等于32 则认为是中心区域。            // java.lang.Math.sqrt(x*x + y*y)  勾股定理 算半径。            boolean inCenter = java.lang.Math.sqrt(x*x + y*y) <= CENTER_RADIUS;            switch (event.getAction()) {                case MotionEvent.ACTION_DOWN:                    mTrackingCenter = inCenter;                    //按下动作触发时,如果点击的是中心,则高亮中间部分。                    if (inCenter) {                        mHighlightCenter = true;                        invalidate();                        break;                    }                case MotionEvent.ACTION_MOVE:                //监听移动动作,如果是中心部位,则高亮,                //否则随着手的移动,获取对应颜色设置中心部位颜色                    if (mTrackingCenter) {                        if (mHighlightCenter != inCenter) {                            mHighlightCenter = inCenter;                            invalidate();                        }                    } else {                                             float angle = (float)java.lang.Math.atan2(y, x);                        // need to turn angle [-PI ... PI] into unit [0....1]                        //将角度 转换为【0,1】区间的值。如果为负数则加1,。                        float unit = angle/(2*PI);                        if (unit < 0) {                            unit += 1;                        }                        //取色的关键部位                        mCenterPaint.setColor(interpColor(mColors, unit));                        invalidate();                    }                    break;                case MotionEvent.ACTION_UP:                //监听松手动作时,如果是从中心部位松手,则取消对话框。否则中心标志位置false                //然后重新绘图。                    if (mTrackingCenter) {                        if (inCenter) {                            mListener.colorChanged(mCenterPaint.getColor());                        }                        mTrackingCenter = false;    // so we draw w/o halo                        invalidate();                    }                    break;            }            return true;        }    }    /**     *      * @param context :always is the context of activity     * @param listener: the OnColorChangedListener listen the change of color     * @param initialColor: initial the color of the ColorPickerDialog     */    public ColorPickerDialog(Context context,                             OnColorChangedListener listener,                             int initialColor) {        super(context);        mListener = listener;        mInitialColor = initialColor;    }    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        //dismiss the dialog if the color is selected.        //对话框取色中间被点击时,监听到颜色已经选定,则消失对话框。        OnColorChangedListener l = new OnColorChangedListener() {            public void colorChanged(int color) {                mListener.colorChanged(color);                dismiss();            }        };        //set the colorPickerView to the content view of dialog         setContentView(new ColorPickerView(getContext(), l, mInitialColor));       //set title of dialog        setTitle("Pick a Color");    }}</span>

3、在布局文件activity_main.xml中添加一个button 代码如下:

<span style="font-size:18px;"><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context=".MainActivity" >        <Button        android:id="@+id/btnGetColorDia"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentLeft="true"        android:layout_alignParentRight="true"        android:layout_alignParentTop="true"        android:textSize="20dp"        android:text="对话框方式获取颜色" /> </RelativeLayout></span>

4、在MainActivity中调用 ColorPickerDialog。点击button的时候,显示dialog。
代码如下:
<span style="font-size:18px;">package demo.dim.getcolordemo;import android.app.Activity;import android.graphics.Color;import android.os.Bundle;import android.view.Menu;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import demo.dim.getcolordemo.ColorPickerDialog.OnColorChangedListener;public class MainActivity extends Activity {private final static String TAG="GET COLOR DEMO-->>";private ColorPickerDialog ColorPicker=null;private Button btnGetColorDia=null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btnGetColorDia=(Button)findViewById(R.id.btnGetColorDia);btnGetColorDia.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubColorPicker.show();}});<strong>ColorPicker=new ColorPickerDialog(this, new OnColorChangedListener() {@Overridepublic void colorChanged(int color) {// TODO Auto-generated method stubbtnGetColorDia.setBackgroundColor(color);}}, Color.BLUE);</strong>}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.activity_main, menu);return true;}}</span>

先看看运行效果:



三、介绍色盘取色步骤:

1、在以上工程基础上,增加一个类。这里命名为:ColorPickerView
代码如下:
<span style="font-size:18px;">package demo.dim.getcolordemo; 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.Paint;import android.graphics.PointF;import android.graphics.Rect;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.View;public class ColorPickerView extends View{private String TAG="colorPicker";private boolean DBG=false;    private Context mContext;private Paint mRightPaint;            //画笔private int mHeight;                  //view高private int mWidth;                   //view宽private int[] mRightColors;private int LEFT_WIDTH;private Bitmap mLeftBitmap;private Bitmap mLeftBitmap2; private Paint mBitmapPaint;private PointF mLeftSelectPoint; private OnColorChangedListenerD mChangedListenerD; private boolean mLeftMove = false;private float mLeftBitmapRadius;private Bitmap mGradualChangeBitmap;private Bitmap bitmapTemp;private int mCallBackColor = Integer.MAX_VALUE;int newWidgth;int newHeigh;    public static String hexColor="FFFFFF";public static int ColorText=0;private  Canvas mCan=null;public ColorPickerView(Context context) {this(context, null);}public ColorPickerView(Context context, AttributeSet attrs) {super(context, attrs);mContext = context;init();} public void setOnColorChangedListennerD(OnColorChangedListenerD listener) {mChangedListenerD = listener;}private void init() {bitmapTemp = BitmapFactory.decodeResource(getResources(), R.drawable.piccolor); 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(0, 0);  newWidgth=BitmapFactory.decodeResource(getResources(), R.drawable.piccolor).getWidth(); newHeigh=BitmapFactory.decodeResource(getResources(), R.drawable.piccolor).getHeight();  } //important patient please!!!@Overrideprotected void onDraw(Canvas canvas) { //mCan=canvas;canvas.drawBitmap(getGradual() , null , new Rect(0, 0, LEFT_WIDTH , mHeight ), mBitmapPaint);  if(!hexColor.equals("ffffff")){System.out.println(TAG+"draw2");if (mLeftMove) {canvas.drawBitmap(mLeftBitmap, mLeftSelectPoint.x - mLeftBitmapRadius,mLeftSelectPoint.y - mLeftBitmapRadius, mBitmapPaint); } else {try {canvas.drawBitmap(mLeftBitmap2, mLeftSelectPoint.x - mLeftBitmapRadius, mLeftSelectPoint.y - mLeftBitmapRadius, mBitmapPaint);} catch (Exception e) {// TODO: handle exception}} }}@Overrideprotected 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 = newHeigh;}if (heightMode == MeasureSpec.EXACTLY) {mHeight = height;} else {mHeight = newHeigh;}LEFT_WIDTH = mWidth;setMeasuredDimension(mWidth, mHeight);}@Overridepublic boolean onTouchEvent(MotionEvent event) {float x = event.getX();float y = event.getY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:ColorText=getLeftColor(x, y);//System.out.println("color num="+getLeftColor(x, y)); if(getLeftColor(x, y)!=-1)    invalidate(); case MotionEvent.ACTION_MOVE:{try {//mLeftMove = true; if(getLeftColor(x, y)!=-1){ColorText=getLeftColor(x, y);proofLeft(x, y);int rmove = Color.red(ColorText);int gmove = Color.green(ColorText);int bmove = Color.blue(ColorText); //System.out.println("color rgb");String r11=Integer.toHexString(rmove);String g11=Integer.toHexString(gmove);String b11=Integer.toHexString(bmove);String colorStr1=r11+g11+b11;    //十六进制的颜色字符串。 //System.out.println("color="+colorStr1); hexColor=colorStr1; mChangedListenerD.onColorChanged(ColorText, colorStr1);//changeBGLIS.onColorChanged(ColorText);   invalidate();}} catch (Exception e) {// TODO: handle exception //invalidate();}}break;case MotionEvent.ACTION_UP:try {if(getLeftColor(x, y)!=-1){ColorText=getLeftColor(x, y);//System.out.println("color="+ColorText); mLeftMove = false;int rup = Color.red(ColorText); int gup= Color.green(ColorText);int bup = Color.blue(ColorText); //System.out.println("color rgb");String rupStr=Integer.toHexString(rup);String gupStr=Integer.toHexString(gup);String bupStr=Integer.toHexString(bup);String colorUpStr=rupStr+gupStr+bupStr;    //十六进制的颜色字符串。  System.out.println("color="+colorUpStr); hexColor=colorUpStr;mChangedListenerD.onColorChanged(ColorText, colorUpStr);invalidate();}} catch (Exception e) {// TODO: handle exception// invalidate();}              }return true;}@Overrideprotected 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();}super.onDetachedFromWindow();}private Bitmap getGradual() {if (mGradualChangeBitmap == null) {Paint leftPaint = new Paint();leftPaint.setStrokeWidth(1); mGradualChangeBitmap = Bitmap.createBitmap(LEFT_WIDTH, mHeight, Config.RGB_565);mGradualChangeBitmap.eraseColor(Color.WHITE);Canvas canvas = new Canvas(mGradualChangeBitmap);      canvas.drawBitmap( bitmapTemp, null , new Rect(0, 0, LEFT_WIDTH , mHeight ), mBitmapPaint);}return mGradualChangeBitmap;}// 校正xyprivate void proofLeft(float x, float y) {if (x < 0) {mLeftSelectPoint.x = 0;} else if (x > (LEFT_WIDTH)) {mLeftSelectPoint.x = LEFT_WIDTH;} else {mLeftSelectPoint.x = x;}if (y < 0) {mLeftSelectPoint.y = 0;} else if (y > (mHeight - 0)) {mLeftSelectPoint.y = mHeight - 0;} else {mLeftSelectPoint.y = y;}}private int getLeftColor(float x, float y) {Bitmap temp = getGradual();// 为了防止越界int intX = (int) x;int intY = (int) y;if(intX<0)intX=0;if(intY<0)intY=0;if (intX >= temp.getWidth()) {intX = temp.getWidth() - 1;}if (intY >= temp.getHeight()) {intY = temp.getHeight() - 1;} System.out.println("leftColor"+temp.getPixel(intX, intY));        return temp.getPixel(intX, intY);}     // ### 内部类 ###public interface OnColorChangedListenerD {void onColorChanged(int color, String hexStrColor);} }</span>

 2、在布局文件activity_main.xml中添加一个button 并添加ColorPickerView 代码如下:
<span style="font-size:18px;"><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context=".MainActivity" >        <Button        android:id="@+id/btnGetColorDia"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentLeft="true"        android:layout_alignParentRight="true"        android:layout_alignParentTop="true"        android:textSize="20dp"        android:text="对话框方式获取颜色" /> <strong>   <Button        android:id="@+id/btnColorDisk"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentLeft="true"        android:layout_alignParentRight="true"        android:layout_below="@+id/btnGetColorDia"        android:text="从色盘吸管获取颜色" />    <demo.dim.getcolordemo.ColorPickerView        android:id="@+id/colorPickerDisk"        android:layout_width="wrap_content"        android:layout_height="wrap_content"         android:layout_below="@+id/btnColorDisk"        android:layout_alignParentTop="true"        android:layout_marginTop="150dp"        android:visibility="invisible"          /></strong></RelativeLayout></span>

3、修改MainActivity中代码如下:
<span style="font-size:18px;">package demo.dim.getcolordemo;import android.app.Activity;import android.graphics.Color;import android.os.Bundle;import android.view.Menu;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import demo.dim.getcolordemo.ColorPickerDialog.OnColorChangedListener;import demo.dim.getcolordemo.ColorPickerView .OnColorChangedListenerD;public class MainActivity extends Activity {/** * Tag of this class, more clear and convenient when you debugging  */private final static String TAG="GET COLOR DEMO-->>";/** * the object of the ColorPickerDialog */private ColorPickerDialog ColorPicker=null;/** * btnGetColorDia   use to trigger the dialog of color when the button is click  */private Button btnGetColorDia=null;<span style="color:#ff6666;">/** * color Disk  */ColorPickerView colorPickerDisk=null;/** * button of colorDisk */Button btnColorDisk=null;</span>/** *  */int intChange=1;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);<span style="color:#ff6666;">colorPickerDisk=new ColorPickerView(this);//find the ID of ViewcolorPickerDisk=(ColorPickerView)findViewById(R.id.colorPickerDisk); btnColorDisk=(Button)findViewById(R.id.btnColorDisk);</span>btnGetColorDia=(Button)findViewById(R.id.btnGetColorDia);btnGetColorDia.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubColorPicker.show();}});<span style="color:#ff6666;">//how to use ColorPickerDialog Class  ,the default color is blue ,here is Color.BLUEColorPicker=new ColorPickerDialog(this, new OnColorChangedListener() {@Overridepublic void colorChanged(int color) {// TODO Auto-generated method stub//change the background  of button when the color is changed .btnGetColorDia.setBackgroundColor(color);}}, Color.BLUE);colorPickerDisk.setOnColorChangedListennerD(new OnColorChangedListenerD() {@Overridepublic void onColorChanged(int color, String hexStrColor) {// TODO Auto-generated method stubbtnColorDisk.setBackgroundColor(color);btnColorDisk.setText("Color is "+hexStrColor);}}); btnColorDisk.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stub if(intChange%2==0) {  colorPickerDisk.setVisibility(View.INVISIBLE); }else { colorPickerDisk.setVisibility(View.VISIBLE); } intChange++;}});}</span>@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.activity_main, menu);return true;}}</span>

效果图如下:

 
RGB 查询工具网址: http://rgb.phpddt.com/

希望这篇小文章,对有需要的人有所帮助。

如有有问题!互相讨论!共同进步! 


源码请点击这里。或加群:383012091 讨论。

0 0