android 通过修改图片像素实现CircleImageView
CircleImageView实现方法有很多种,各有优缺点,因此需要按照不同的场景使用。我们今天使用修改图片像素的方法实现CircleImageView,主要知识点无非是勾股定理和点到圆形的距离。
素材图片:
效果如下:
1、clipPath裁剪画布
该方法支持的最小版本是Android 4.3(API Level 18),方便快捷,但是不支持硬件加,此外也存在Path既有的缺点,不支持抗锯齿。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pic);
mPath = new Path();
mPath.addCircle(mBitmap.getWidth() / 2, mBitmap.getHeight() / 2, mBitmap.getWidth() / 2, Path.Direction.CCW);
canvas.clipPath(mPath);
canvas.drawBitmap(mBitmap, 0, 0, paint);
}
2、使用PorterDuffXfermode
PorterDuffXfermode是Android主流的图片合成工具,支持模式多,稳定性强,效果好,质量高,支持抗锯齿备受广大开发者喜爱,可以说是很多应用开发的首选。缺点是难度学习有些高,另外比较占内存。
/**
* 绘制圆形图片
*
*/
@Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
if (null != drawable) {
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
Bitmap b = getCircleBitmap(bitmap);
final Rect rectSrc = new Rect(0, 0, b.getWidth(), b.getHeight());
final Rect rectDest = new Rect(0,0,getWidth(),getHeight());
paint.reset();
canvas.drawBitmap(b, rectSrc, rectDest, paint);
} else {
super.onDraw(canvas);
}
}
/**
* 获取圆形图片方法
* @param bitmap
* @param pixels
* @return Bitmap
*/
private Bitmap getCircleBitmap(Bitmap bitmap) {
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
paint.setAntiAlias(true);
canvas.drawColor(Color.TRANSPARENT);
paint.setColor(color);
int x = bitmap.getWidth();
canvas.drawCircle(x / 2, x / 2, x / 2, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
4、设置画笔Paint的Shader,然后用该画笔绘制圆形图片
该方法是Glide和picasso使用的方法,用法简单便捷,占内占有率处于中等水平。
@Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
if (null != drawable) {
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
Bitmap b = transform(bitmap);
final Rect rectSrc = new Rect(0, 0, b.getWidth(), b.getHeight());
final Rect rectDest = new Rect(0,0,getWidth(),getHeight());
paint.reset();
canvas.drawBitmap(b, rectSrc, rectDest, paint);
} else {
super.onDraw(canvas);
}
}
public Bitmap transform(Bitmap source) {
int size = Math.min(source.getWidth(), source.getHeight());
int x = (source.getWidth() - size) / 2;
int y = (source.getHeight() - size) / 2;
Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size);
if (squaredBitmap != source) {
source.recycle();
}
Bitmap bitmap = Bitmap.createBitmap(size, size, source.getConfig());
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
BitmapShader shader = new BitmapShader(squaredBitmap,
BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
float mScale = (mRadius * 2.0f) / Math.min(bitmap.getHeight(), bitmap.getWidth());
Matrix matrix = new Matrix();
matrix.setScale(mScale, mScale);
bitmapShader.setLocalMatrix(matrix);
paint.setShader(shader);
paint.setAntiAlias(true);
float r = size / 2f;
canvas.drawCircle(r, r, r, paint);
squaredBitmap.recycle();
return bitmap;
}
5、修改像素
该方法无法支持抗锯齿,并且不支持Bitmap.Config.HARDWARE格式的bitmap,但用法简单,内存占有率同样处于比较低。
public class CircleImageView extends AppCompatImageView {
public CircleImageView(Context context) {
this(context,null);
}
public CircleImageView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public void onDraw(Canvas canvas) {
int width = getWidth();
int height = getHeight();
int minSize = Math.min(width,height)/2;
Drawable drawable = getDrawable();
if(drawable!=null && minSize!=0) {
if(Math.min(drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight())==0) {
return;
}
int intrinsicWidth = drawable.getIntrinsicWidth();
int intrinsicHeight = drawable.getIntrinsicHeight();
float R = Math.min(intrinsicWidth, intrinsicHeight) / 2;
Bitmap bmp = transformBitmap(drawable, intrinsicWidth, intrinsicHeight, R);
Matrix imageMatrix = getImageMatrix();
if((imageMatrix==null || imageMatrix.isIdentity()) && getPaddingTop()==0 && getPaddingLeft()==0){
drawCircleImage(canvas, bmp);
}else {
if (imageMatrix != null && !imageMatrix.isIdentity()) {
canvas.concat(imageMatrix);
}
final int saveCount = canvas.getSaveCount();
canvas.save();
if (getCropToPadding()) {
final int scrollX = getScrollX();
final int scrollY = getScrollY();
canvas.clipRect(scrollX + getPaddingLeft(), scrollY + getPaddingTop(),
scrollX + getRight() - getLeft() - getPaddingRight(),
scrollY + getBottom() - getTop() - getPaddingBottom());
}
canvas.translate(getPaddingLeft(), getPaddingTop());
drawCircleImage(canvas, bmp);
canvas.restoreToCount(saveCount);
}
if(bmp!=null && !bmp.isRecycled()) {
bmp.recycle();
}
}else{
super.onDraw(canvas);
}
}
private void drawCircleImage(Canvas canvas, Bitmap bmp) {
try {
DrawFilter drawFilter = canvas.getDrawFilter();
canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));
canvas.drawBitmap(bmp, 0, 0, null);
canvas.setDrawFilter(drawFilter);
}catch (Exception e){
e.printStackTrace();
return;
}
}
@NonNull
private Bitmap transformBitmap(Drawable drawable, int intrinsicWidth, int intrinsicHeight, float r) {
Bitmap bmp = Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888);
Canvas targetCanvas = new Canvas(bmp);
try {
drawable.draw(targetCanvas);
for (int y = 0; y < intrinsicHeight; y++) {
for (int x = 0; x < intrinsicWidth; x++) {
if ((Math.pow(x - intrinsicWidth / 2, 2) + Math.pow(y - intrinsicHeight / 2, 2)) <= Math.pow(r, 2)) {
continue;
}
bmp.setPixel(x, y, Color.TRANSPARENT);
}
}
}catch (Exception e){
NCFLog.e("transformBitmap","e="+e.getLocalizedMessage());
e.printStackTrace();
}
return bmp;
}
public boolean isHardware(Bitmap sourceBitmap){
if(sourceBitmap==null) return false;
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O) {
return sourceBitmap.getConfig() == Bitmap.Config.HARDWARE;
}
return false;
}
}

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
偏向锁到底是怎么回事啊啊啊啊
微信公众号:IT一刻钟 。大型现实非严肃主义现场 一刻钟与你分享优质技术架构与见闻,做一个有剧情的程序员。 关注可第一时间了解更多精彩内容,定期有福利相送哟。 话说有这么一件事。 于是当天夜里,小哥哥便哼哧哼哧的画出了偏向锁的逻辑图。 其逻辑呢,各位看官待我慢慢道来。 看一张大图 (点击看大图) 流程讲解 当JVM启用了偏向锁模式(JDK6以上默认开启),新创建对象的Mark Word中的Thread Id为0,说明此时处于可偏向但未偏向任何线程,也叫做匿名偏向状态(anonymously biased)。 偏向锁逻辑 1.线程A第一次访问同步块时,先检测对象头Mark Word中的标志位是否为01,依此判断此时对象锁是否处于无所状态或者偏向锁状态(匿名偏向锁); 2.然后判断偏向锁标志位是否为1,如果不是,则进入轻量级锁逻辑(使用CAS竞争锁),如果是,则进入下一步流程; 3.判断是偏向锁时,检查对象头Mark Word中记录的Thread Id是否是当前线程ID,如果是,则表明当前线程已经获得对象锁,以后该线程进入同步块时,不需要CAS进行加锁,只会往当前线程的栈中添加一条Disp...
-
下一篇
tensorflow 之循环神经网络
应用场景: 应用于语音识别 语音翻译 机器翻译 RNN RNN(Recurrent Neural Networks,循环神经网络)不仅会学习当前时刻的信息,也会依赖之前的序列信息。 由于其特殊的网络模型结构解决了信息保存的问题。所以RNN对处理时间序列和语言文本序列问题有独特的优势。递归神经网络都具有一连串重复神经网络模块的形式。在标准的RNNs中,这种重复模块有一种非常简单的结构。 那么S(t+1) = tanh( UX(t+1) + WS(t))。tanh激活函数图像如下: 激活函数tanh把状态S值映射到-1和1之间. RNN通过BPTT算法反向传播误差,它与BP相似,只不过与时间有关。RNN同样通过随机梯度下降(Stochastic gradient descent)算法使得代价函数(损失函数)值达到最小。 但是随着时间间隔不断增大时,RNN会丧失学习到连接很远的信息能力(梯度消失)。原因如下: RNN的激活函数tanh可以将所有值映射到-1至1之间,以及在利用梯度下降算法调优时利用链式法则,那么会造成很多个小于1的项连乘就很快的逼近零。 依赖于我们的激活函数和网络参数,也可能...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2整合Redis,开启缓存,提高访问速度
- 2048小游戏-低调大师作品
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- SpringBoot2全家桶,快速入门学习开发网站教程
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- MySQL8.0.19开启GTID主从同步CentOS8
- SpringBoot2更换Tomcat为Jetty,小型站点的福音