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>
代码如下:
<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;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnGetColorDia=(Button)findViewById(R.id.btnGetColorDia);
btnGetColorDia.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
ColorPicker.show();
}
});
<strong> ColorPicker=new ColorPickerDialog(this, new OnColorChangedListener() {
@Override
public void colorChanged(int color) {
// TODO Auto-generated method stub
btnGetColorDia.setBackgroundColor(color);
}
}, Color.BLUE);</strong>
}
@Override
public 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!!!
@Override
protected 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
}
}
}
}
@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 = newHeigh;
}
if (heightMode == MeasureSpec.EXACTLY) {
mHeight = height;
} else {
mHeight = newHeigh;
}
LEFT_WIDTH = mWidth;
setMeasuredDimension(mWidth, mHeight);
}
@Override
public 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;
}
@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();
}
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;
}
// 校正xy
private 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;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
<span style="color:#ff6666;"> colorPickerDisk=new ColorPickerView(this);
//find the ID of View
colorPickerDisk=(ColorPickerView)findViewById(R.id.colorPickerDisk);
btnColorDisk=(Button)findViewById(R.id.btnColorDisk);</span>
btnGetColorDia=(Button)findViewById(R.id.btnGetColorDia);
btnGetColorDia.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
ColorPicker.show();
}
});
<span style="color:#ff6666;">//how to use ColorPickerDialog Class ,the default color is blue ,here is Color.BLUE
ColorPicker=new ColorPickerDialog(this, new OnColorChangedListener() {
@Override
public 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() {
@Override
public void onColorChanged(int color, String hexStrColor) {
// TODO Auto-generated method stub
btnColorDisk.setBackgroundColor(color);
btnColorDisk.setText("Color is "+hexStrColor);
}
});
btnColorDisk.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(intChange%2==0)
{
colorPickerDisk.setVisibility(View.INVISIBLE);
}else
{
colorPickerDisk.setVisibility(View.VISIBLE);
}
intChange++;
}
});
}</span>
@Override
public 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/
希望这篇小文章,对有需要的人有所帮助。
如有有问题!互相讨论!共同进步!