Android 不规则封闭区域填充 手指秒变油漆桶,Android经典面试

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注Android)
img

正文

我们代码中引入了一个边界颜色,如果设置的话,着色的边界参考为该边界颜色,否则会只要与种子颜色不一致为边界。

(一)构造方法与测量

public class ColourImageView extends ImageView

{

private Bitmap mBitmap;

/**

  • 边界的颜色

*/

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);

}

可以看到我们选择的是继承ImageView,这样只需要将图片设为src即可。

构造方法中获取我们的自定义边界颜色,当然可以不设置~~

重写测量的目的是为了获取一个和View一样大小的Bitmap便于我们操作。

接下来就是点击啦~

(二)onTouchEvent

@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);

}

/**

  • 根据x,y获得改点颜色,进行填充

  • @param x

  • @param y

*/

private void fillColorToSameArea(int x, int y)

{

Bitmap bm = mBitmap;

int pixel = bm.getPixel(x, y);

if (pixel == Color.TRANSPARENT || (hasBorderColor && mBorderColor == pixel))

{

return;

}

int 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));

}

可以看到,我们在onTouchEvent中获取(x,y),然后拿到改点坐标:

  • 获得点击点颜色,获得整个bitmap的像素数组

  • 改变这个数组中的颜色

  • 然后重新设置给bitmap,重新设置给ImageView

重点就是通过fillColor去改变数组中的颜色

/**

  • @param pixels 像素数组

  • @param w 宽度

  • @param h 高度

  • @param pixel 当前点的颜色

  • @param newColor 填充色

  • @param i 横坐标

  • @param j 纵坐标

*/

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));

//步骤2:判断栈是否为空,

// 如果栈为空则结束算法,否则取出栈顶元素作为当前扫描线的种子点(x, y),

// y是当前的扫描线;

while (!mStacks.isEmpty())

{

/**

  • 步骤3:从种子点(x, y)出发,沿当前扫描线向左、右两个方向填充,

  • 直到边界。分别标记区段的左、右端点坐标为xLeft和xRight;

*/

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;

/**

  • 步骤4:

  • 分别检查与当前扫描线相邻的y - 1和y + 1两条扫描线在区间[xLeft, xRight]中的像素,

  • 从xRight开始向xLeft方向搜索,假设扫描的区间为AAABAAC(A为种子点颜色),

  • 那么将B和C前面的A作为种子点压入栈中,然后返回第(2)步;

*/

//从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);

}

}

可以看到我已经很清楚的将该算法的四个步骤标识到该方法中。好了,最后就是一些依赖的细节上的方法:

/**

  • 在新行找种子节点

  • @param pixels

  • @param pixel

  • @param w

  • @param h

  • @param i

  • @param left

  • @param 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;

/**

  • 从end到begin,找到种子节点入栈(AAABAAAB,则B前的A为种子节点)

*/

while (end >= begin)

{

if (pixels[end] == pixel)

{

if (!hasSeed)

{

rx = end % w;

mStacks.push(new Point(rx, ry));

hasSeed = true;

}

} else

{

hasSeed = false;

}

end–;

}

}

/**

  • 往右填色,返回填充的个数

  • @return

*/

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;

}

/**

  • 往左填色,返回填色的数量值

  • @return

*/

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;

}

}

/**

  • 返回一个随机颜色

  • @return

*/

private int randomColor()

{

Random random = new Random();

int color = Color.argb(255, random.nextInt(256), random.nextInt(256), random.nextInt(256));

return color;

}

ok,到此,代码就介绍完毕了~~~

最后贴下布局文件~~

最后

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

上面分享的百度、腾讯、网易、字节跳动、阿里等公司2021年的高频面试题,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。

【Android思维脑图(技能树)】

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

【Android高级架构视频学习资源】

**Android部分精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

**,由于篇幅有限,上面只是以图片的形式给大家展示一部分。

【Android思维脑图(技能树)】

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

[外链图片转存中…(img-pWZsryMm-1713664351117)]

【Android高级架构视频学习资源】

**Android部分精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-vjvHt5nl-1713664351117)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 29
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值