点击跳转参考文章
-
本文参考鸿洋大佬的博客 ,解决了当填充颜色一致时,连续点击同一位置会引发死循环/程序崩溃的bug ,并可以自定义一些色板
-
效果图如下
-
布局代码如下
- 自定义一个ColourImageView类
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ImageView;
import java.util.Random;
import java.util.Stack;
@SuppressLint("AppCompatCustomView")
public class ColourImageView extends ImageView {
private static int mtype;//1是自定义 2是随机
private Bitmap mBitmap;
private static int mColor=-1;//默认颜色是白色
private static int oldColor;
private int newColor;
private int iswhith=0;
private int isheight=0;
private int mBorderColor = -1;
private boolean hasBorderColor = false;
private Stack mStacks = new Stack();
public ColourImageView(Context context, AttributeSet attrs){
super(context, attrs);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ColourImageView);
mBorderColor = ta.getColor(R.styleable.ColourImageView_border_color, -1);
hasBorderColor = (mBorderColor != -1);
L.e("hasBorderColor = " + hasBorderColor + " , mBorderColor = " + mBorderColor);
ta.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int viewWidth = getMeasuredWidth();
int viewHeight = getMeasuredHeight();
//以宽度为标准,等比例缩放view的高度
setMeasuredDimension(viewWidth,
getDrawable().getIntrinsicHeight() * viewWidth / getDrawable().getIntrinsicWidth());
L.e("view's width = " + getMeasuredWidth() + " , view's height = " + getMeasuredHeight());
//根据drawable,去得到一个和view一样大小的bitmap
BitmapDrawable drawable = (BitmapDrawable) getDrawable();
Bitmap bm = drawable.getBitmap();
mBitmap = Bitmap.createScaledBitmap(bm, getMeasuredWidth(), getMeasuredHeight(), false);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
final int x = (int) event.getX();
final int y = (int) event.getY();
if (event.getAction() == MotionEvent.ACTION_DOWN) {
fillColorToSameArea(x, y);
}
return super.onTouchEvent(event);
}
private void fillColorToSameArea(int x, int y) {
Bitmap bm = mBitmap;
int pixel = bm.getPixel(x, y);
if (pixel == Color.TRANSPARENT || (hasBorderColor && mBorderColor == pixel))
{
return;
}
if (mtype==1){
newColor = mColor;
}else {
newColor = randomColor();
}
int w = bm.getWidth();
int h = bm.getHeight();
//拿到该bitmap的颜色数组
int[] pixels = new int[w * h];
bm.getPixels(pixels, 0, w, 0, 0, w, h);
//填色
fillColor(pixels, w, h, pixel, newColor, x, y);
//重新设置bitmap
bm.setPixels(pixels, 0, w, 0, 0, w, h);
setImageDrawable(new BitmapDrawable(bm));
}
public static void getColorId(int acolor) {
mColor=acolor;
}
public static void getType(int type) {
mtype=type;
}
private void fillColor(int[] pixels, int w, int h, int pixel, int newColor, int i, int j) {
//步骤1:将种子点(x, y)入栈;
mStacks.push(new Point(i, j));
if (pixel==newColor && newColor==oldColor){
return;
}
//步骤2:判断栈是否为空,
// 如果栈为空则结束算法,否则取出栈顶元素作为当前扫描线的种子点(x, y),
// y是当前的扫描线;
while (!mStacks.isEmpty()) {
Point seed = mStacks.pop();
//L.e("seed = " + seed.x + " , seed = " + seed.y);
int count = fillLineLeft(pixels, pixel, w, h, newColor, seed.x, seed.y);
int left = seed.x - count + 1;
count = fillLineRight(pixels, pixel, w, h, newColor, seed.x + 1, seed.y);
int right = seed.x + count;
oldColor=newColor;
//从y-1找种子
if (seed.y - 1 >= 0){
findSeedInNewLine(pixels, pixel, w, h, seed.y - 1, left, right);
}
//从y+1找种子
if (seed.y + 1 < h){
findSeedInNewLine(pixels, pixel, w, h, seed.y + 1, left, right);
}
}
}
private void findSeedInNewLine(int[] pixels, int pixel, int w, int h, int i, int left, int right) {
int begin = i * w + left;
int end = i * w + right;
boolean hasSeed = false;
int rx = -1, ry = -1;
ry = i;
while (end >= begin) {
if (pixels[end] == pixel) {
if (!hasSeed) {
rx = end % w;
mStacks.push(new Point(rx, ry));
hasSeed = true;
}
} else {
hasSeed = false;
}
end--;
}
}
private int fillLineRight(int[] pixels, int pixel, int w, int h, int newColor, int x, int y) {
int count = 0;
while (x < w)
{
//拿到索引
int index = y * w + x;
if (needFillPixel(pixels, pixel, index))
{
pixels[index] = newColor;
count++;
x++;
} else
{
break;
}
}
return count;
}
private int fillLineLeft(int[] pixels, int pixel, int w, int h, int newColor, int x, int y) {
int count = 0;
while (x >= 0)
{
//计算出索引
int index = y * w + x;
if (needFillPixel(pixels, pixel, index))
{
pixels[index] = newColor;
count++;
x--;
} else
{
break;
}
}
return count;
}
private boolean needFillPixel(int[] pixels, int pixel, int index) {
if (hasBorderColor)
{
return pixels[index] != mBorderColor;
} else
{
return pixels[index] == pixel;
}
}
private static int randomColor() {
Random random = new Random();
int color = Color.argb(255, random.nextInt(256), random.nextInt(256), random.nextInt(256));
return color;
}
}
- R.styleable.ColourImageView
- ColourImageView所在位置
- Log统一管理类
import android.util.Log;
public class L
{
private L()
{
throw new UnsupportedOperationException("cannot be instantiated");
}
public static boolean isDebug = true;// 是否需要打印bug,可以在application的onCreate函数里面初始化
private static final String TAG = "fyh";
// 下面四个是默认tag的函数
public static void i(String msg)
{
if (isDebug)
Log.i(TAG, msg);
}
public static void d(String msg)
{
if (isDebug)
Log.d(TAG, msg);
}
public static void e(String msg)
{
if (isDebug)
Log.e(TAG, msg);
}
public static void v(String msg)
{
if (isDebug)
Log.v(TAG, msg);
}
// 下面是传入自定义tag的函数
public static void i(String tag, String msg)
{
if (isDebug)
Log.i(tag, msg);
}
public static void d(String tag, String msg)
{
if (isDebug)
Log.i(tag, msg);
}
public static void e(String tag, String msg)
{
if (isDebug)
Log.i(tag, msg);
}
public static void v(String tag, String msg)
{
if (isDebug)
Log.i(tag, msg);
}
}
- MainActivity类的处理
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private Button btn_red,btn_green,btn_blue,btn_black,suiji,btn_white,qiehuan;
private int isqh=1;
private ColourImageView image1,image2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
initView();
onClick();
}
private void initView() {
btn_red=findViewById(R.id.btn_red);
btn_green=findViewById(R.id.btn_green);
btn_blue=findViewById(R.id.btn_blue);
suiji=findViewById(R.id.suiji);
btn_white=findViewById(R.id.btn_white);
qiehuan=findViewById(R.id.qiehuan);
image1=findViewById(R.id.image1);
image2=findViewById(R.id.image2);
btn_black=findViewById(R.id.btn_black);
//默认给随机的动画
Animation scale= AnimationUtils.loadAnimation(getApplication(),R.anim.scale);
suiji.startAnimation(scale);
}
private void onClick() {
btn_red.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ColourImageView.getColorId(Color.RED);
ColourImageView.getType(1);
btn_red.setBackgroundResource(R.drawable.btnred1);
btn_green.setBackgroundResource(R.drawable.btngreen);
btn_blue.setBackgroundResource(R.drawable.btnblue);
suiji.setBackgroundResource(R.drawable.btn1);
btn_black.setBackgroundResource(R.drawable.btnblack);
btn_white.setBackgroundResource(R.drawable.btnwhite);
Animation scale= AnimationUtils.loadAnimation(getApplication(),R.anim.scale);
btn_red.startAnimation(scale);
btn_green.clearAnimation();
btn_blue.clearAnimation();
btn_black.clearAnimation();
btn_white.clearAnimation();
suiji.clearAnimation();
}
});
btn_green.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ColourImageView.getColorId(Color.GREEN);
ColourImageView.getType(1);
btn_red.setBackgroundResource(R.drawable.btnred);
btn_green.setBackgroundResource(R.drawable.btngreen1);
btn_blue.setBackgroundResource(R.drawable.btnblue);
suiji.setBackgroundResource(R.drawable.btn1);
btn_black.setBackgroundResource(R.drawable.btnblack);
btn_white.setBackgroundResource(R.drawable.btnwhite);
Animation scale= AnimationUtils.loadAnimation(getApplication(),R.anim.scale);
btn_green.startAnimation(scale);
btn_red.clearAnimation();
btn_blue.clearAnimation();
btn_black.clearAnimation();
btn_white.clearAnimation();
suiji.clearAnimation();
}
});
btn_blue.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ColourImageView.getColorId(Color.BLUE);
ColourImageView.getType(1);
btn_red.setBackgroundResource(R.drawable.btnred);
btn_green.setBackgroundResource(R.drawable.btngreen);
btn_blue.setBackgroundResource(R.drawable.btnblue1);
suiji.setBackgroundResource(R.drawable.btn1);
btn_black.setBackgroundResource(R.drawable.btnblack);
btn_white.setBackgroundResource(R.drawable.btnwhite);
Animation scale= AnimationUtils.loadAnimation(getApplication(),R.anim.scale);
btn_blue.startAnimation(scale);
btn_red.clearAnimation();
btn_green.clearAnimation();
btn_black.clearAnimation();
btn_white.clearAnimation();
suiji.clearAnimation();
}
});
btn_black.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ColourImageView.getColorId(Color.BLACK);
ColourImageView.getType(1);
suiji.setBackgroundResource(R.drawable.btn1);
btn_red.setBackgroundResource(R.drawable.btnred);
btn_green.setBackgroundResource(R.drawable.btngreen);
btn_blue.setBackgroundResource(R.drawable.btnblue);
btn_black.setBackgroundResource(R.drawable.btnblack1);
btn_white.setBackgroundResource(R.drawable.btnwhite);
Animation scale= AnimationUtils.loadAnimation(getApplication(),R.anim.scale);
btn_black.startAnimation(scale);
btn_red.clearAnimation();
btn_green.clearAnimation();
btn_blue.clearAnimation();
btn_white.clearAnimation();
suiji.clearAnimation();
}
});
btn_white.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ColourImageView.getColorId(Color.WHITE);
ColourImageView.getType(1);
suiji.setBackgroundResource(R.drawable.btn1);
btn_red.setBackgroundResource(R.drawable.btnred);
btn_green.setBackgroundResource(R.drawable.btngreen);
btn_blue.setBackgroundResource(R.drawable.btnblue);
btn_black.setBackgroundResource(R.drawable.btnblack);
btn_white.setBackgroundResource(R.drawable.btnwhite1);
Animation scale= AnimationUtils.loadAnimation(getApplication(),R.anim.scale);
btn_white.startAnimation(scale);
btn_red.clearAnimation();
btn_green.clearAnimation();
btn_blue.clearAnimation();
btn_black.clearAnimation();
suiji.clearAnimation();
}
});
suiji.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ColourImageView.getType(2);
suiji.setBackgroundResource(R.drawable.btn2);
btn_red.setBackgroundResource(R.drawable.btnred);
btn_green.setBackgroundResource(R.drawable.btngreen);
btn_blue.setBackgroundResource(R.drawable.btnblue);
btn_black.setBackgroundResource(R.drawable.btnblack);
btn_white.setBackgroundResource(R.drawable.btnwhite);
Animation scale= AnimationUtils.loadAnimation(getApplication(),R.anim.scale);
suiji.startAnimation(scale);
btn_red.clearAnimation();
btn_green.clearAnimation();
btn_blue.clearAnimation();
btn_black.clearAnimation();
btn_white.clearAnimation();
}
});
//切换图片
qiehuan.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (isqh==1){
image2.setVisibility(View.VISIBLE);
image1.setVisibility(View.GONE);
isqh=2;
}else if(isqh==2){
image1.setVisibility(View.VISIBLE);
image2.setVisibility(View.GONE);
isqh=1;
}
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onDestroy() {
super.onDestroy();
btn_red.clearAnimation();
btn_green.clearAnimation();
btn_blue.clearAnimation();
btn_black.clearAnimation();
btn_white.clearAnimation();
suiji.clearAnimation();
}
}



