Android自定义圆形调色板,可设置属性

最近做项目需要用到调色板功能,本着不重复造轮子的想法,找到一个比较好的实现方式:Android 仿PhotoShop调色板应用。拿给老大看,老大说要做成RGB效果,不要HSV,因为不需要黑白色。好吧,吐槽下,最后还是要用HSV的颜色,找了几个,实现效果都不是很好,要不就是不能自定义属性,要不就是画出来是环形,不符合要求,干脆自己重写一个。先看下效果:


看到网上有人用了7种颜色的数组画出一个圆,不太明白什么意思,干脆用iOS的方式,设置一个背景圆,然后触摸的时候取色就可以,这样如果颜色不行的话直接再换张图片就行。下面上码:

首先是在values下attrs.xml自定义几个属性:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="color_picker">

        <!-- 背景圆的半径 -->
        <attr name="circle_radius" format="dimension" />
        <!-- 可滑动小球的半径 -->
        <attr name="center_radius" format="dimension" />
        <!-- 可滑动小球的颜色 -->
        <attr name="center_color" format="color" />
    </declare-styleable>

</resources>
自定义ColorPickView继承View,主要是背景图和中间圆,然后触摸的时候取位置和触摸位置的颜色。注释写的比较详细,应该都能看懂:

package com.xiaowu.colorpicker;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class ColorPickView extends View {
	private Context context;
	private int bigCircle; // 外圈半径
	private int rudeRadius; // 可移动小球的半径
	private int centerColor; // 可移动小球的颜色
	private Bitmap bitmapBack; // 背景图片
	private Paint mPaint; // 背景画笔
	private Paint mCenterPaint; // 可移动小球画笔
	private Point centerPoint;// 中心位置
	private Point mRockPosition;// 小球当前位置
	private OnColorChangedListener listener; // 小球移动的监听
	private int length; // 小球到中心位置的距离

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

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

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

	public void setOnColorChangedListener(OnColorChangedListener listener) {
		this.listener = listener;
	}

	/**
	 * @describe 初始化操作
	 * @param attrs
	 */
	private void init(AttributeSet attrs) {
		// 获取自定义组件的属性
		TypedArray types = context.obtainStyledAttributes(attrs,
				R.styleable.color_picker);
		try {
			bigCircle = types.getDimensionPixelOffset(
					R.styleable.color_picker_circle_radius, 100);
			rudeRadius = types.getDimensionPixelOffset(
					R.styleable.color_picker_center_radius, 10);
			centerColor = types.getColor(R.styleable.color_picker_center_color,
					Color.WHITE);
		} finally {
			types.recycle(); // TypeArray用完需要recycle
		}
		// 将背景图片大小设置为属性设置的直径
		bitmapBack = BitmapFactory.decodeResource(getResources(),
				R.drawable.piccolor);
		bitmapBack = Bitmap.createScaledBitmap(bitmapBack, bigCircle * 2,
				bigCircle * 2, false);
		// 中心位置坐标
		centerPoint = new Point(bigCircle, bigCircle);
		mRockPosition = new Point(centerPoint);
		// 初始化背景画笔和可移动小球的画笔
		mPaint = new Paint();
		mPaint.setAntiAlias(true);
		mCenterPaint = new Paint();
		mCenterPaint.setColor(centerColor);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		// 画背景图片
		canvas.drawBitmap(bitmapBack, 0, 0, mPaint);
		// 画中心小球
		canvas.drawCircle(mRockPosition.x, mRockPosition.y, rudeRadius,
				mCenterPaint);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN: // 按下
			length = getLength(event.getX(), event.getY(), centerPoint.x,
					centerPoint.y);
			if (length > bigCircle - rudeRadius) {
				return true;
			}
			break;
		case MotionEvent.ACTION_MOVE: // 移动
			length = getLength(event.getX(), event.getY(), centerPoint.x,
					centerPoint.y);
			if (length <= bigCircle - rudeRadius) {
				mRockPosition.set((int) event.getX(), (int) event.getY());
			} else {
				mRockPosition = getBorderPoint(centerPoint, new Point(
						(int) event.getX(), (int) event.getY()), bigCircle
						- rudeRadius);
			}
			listener.onColorChange(bitmapBack.getPixel(mRockPosition.x,
					mRockPosition.y));
			break;
		case MotionEvent.ACTION_UP:// 抬起

			break;

		default:
			break;
		}
		invalidate(); // 更新画布
		return true;
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// 视图大小设置为直径
		setMeasuredDimension(bigCircle * 2, bigCircle * 2);
	}

	/**
	 * @describe 计算两点之间的位置
	 * @param x1
	 * @param y1
	 * @param x2
	 * @param y2
	 * @return
	 */
	public static int getLength(float x1, float y1, float x2, float y2) {
		return (int) Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
	}

	/**
	 * @describe 当触摸点超出圆的范围的时候,设置小球边缘位置
	 * @param a
	 * @param b
	 * @param cutRadius
	 * @return
	 */
	public static Point getBorderPoint(Point a, Point b, int cutRadius) {
		float radian = getRadian(a, b);
		return new Point(a.x + (int) (cutRadius * Math.cos(radian)), a.x
				+ (int) (cutRadius * Math.sin(radian)));
	}

	/**
	 * @describe 触摸点与中心点之间直线与水平方向的夹角角度
	 * @param a
	 * @param b
	 * @return
	 */
	public static float getRadian(Point a, Point b) {
		float lenA = b.x - a.x;
		float lenB = b.y - a.y;
		float lenC = (float) Math.sqrt(lenA * lenA + lenB * lenB);
		float ang = (float) Math.acos(lenA / lenC);
		ang = ang * (b.y < a.y ? -1 : 1);
		return ang;
	}

	// 颜色发生变化的回调接口
	public interface OnColorChangedListener {
		void onColorChange(int color);
	}
}

引用的时候很简单,设置好属性就行:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:colorpicker="http://schemas.android.com/apk/res/com.xiaowu.colorpicker"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.xiaowu.colorpicker.ColorPickView
        android:id="@+id/color_picker_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:gravity="center"
        colorpicker:center_color="#FFFFFF"
        colorpicker:center_radius="10dp"
        colorpicker:circle_radius="150dp" />

    <TextView
        android:id="@+id/txt_color"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/color_picker_view"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="37dp"
        android:text="color" />

</RelativeLayout>

写个场景类测试下:

package com.xiaowu.colorpicker;

import com.xiaowu.colorpicker.ColorPickView.OnColorChangedListener;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends Activity {
	private TextView txtColor;
	private ColorPickView myView;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		myView = (ColorPickView) findViewById(R.id.color_picker_view);
		txtColor = (TextView) findViewById(R.id.txt_color);
		myView.setOnColorChangedListener(new OnColorChangedListener() {

			@Override
			public void onColorChange(int color) {
				txtColor.setTextColor(color);
			}

		});
	}

}

代码挺简单,基本都在这了,想直接下载代码的地址在下面:

http://download.csdn.net/detail/zhaoshuiruoli/7832577

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值