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) 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**/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;@Overrideprotected 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);}}@Overrideprotected 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 indexint 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;@Overridepublic boolean onTouchEvent(MotionEvent event) {//setMeasuredDimension(CENTER_X*2, CENTER_Y*2);//这决定了 event.getX() <=200;event.getY()<=200float 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 haloinvalidate();}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;}@Overrideprotected 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 dialogsetTitle("Pick a Color");}}</span>
3、在布局文件activity_main.xml中添加一个button 代码如下:
<span style="font-size:18px;"><RelativeLayout xmlns:android="/apk/res/android"xmlns:tools="/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity" ><Buttonandroid: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="/apk/res/android"xmlns:tools="/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity" ><Buttonandroid: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> <Buttonandroid: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.ColorPickerViewandroid: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 stubif(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 查询工具网址: /
希望这篇小文章,对有需要的人有所帮助。
如有有问题!互相讨论!共同进步!
源码请点击这里。或加群:383012091讨论。