一、自定义ReleativeLayout圆角化
实现:
1.在res目录中新建attrs.xml文件,自定义属性如下。
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="RoundBgRelativeLayout"> <attr name="borderRadius" format="dimension"/><!-- 半径--> <attr name="src" format="reference"/><!-- 图片资源--> </declare-styleable> </resources>
2.新建自定义Layout继承RelativeLayout,重写构造方法。
public class RoundBgRelativeLayout extends RelativeLayout { /** * 圆角大小 */ private int mRadius; /**背景图片*/ private Bitmap mSrc; public RoundBgRelativeLayout(Context context) { this(context,null); } public RoundBgRelativeLayout(Context context, AttributeSet attrs) { this(context, attrs,0); } public RoundBgRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); setWillNotDraw(false); TypedArray arr = context.getTheme().obtainStyledAttributes(attrs, R.styleable.RoundBgRelativeLayout, defStyleAttr, 0); int indexCount = arr.getIndexCount(); for (int i = 0; i < indexCount; i++) { int index = arr.getIndex(i); switch (index){ case R.styleable.RoundBgRelativeLayout_src: mSrc = BitmapFactory.decodeResource(getResources(), arr.getResourceId(index, 0)); break; case R.styleable.RoundBgRelativeLayout_borderRadius: mRadius= (int) arr.getDimension(index,20); break; default: break; } } arr.recycle(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if(mSrc != null){ int width = getMeasuredWidth();//测量宽度 int height = getMeasuredHeight();//测量高度 mSrc = Bitmap.createScaledBitmap(mSrc,width,height,false); canvas.drawBitmap(createRoundImage(mSrc,width,height),0,0,null);//绘制圆角背景 } super.onDraw(canvas); } private Bitmap createRoundImage(Bitmap mSrc, int width, int height) { Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); Bitmap target = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(target); RectF rectF = new RectF(0,0,width,height); //绘制圆角矩形 canvas.drawRoundRect(rectF,mRadius,mRadius,paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));//该模式可以让两个重叠,并取交集 //绘制图片 canvas.drawBitmap(mSrc,0,0,paint); return target; } public void setBgResource(int r){ this.mSrc = BitmapFactory.decodeResource(getResources(),r); invalidate(); } }
实现原理:
主要靠PorterDuff.Mode.SRC_IN 这种模式,第一个图绘制为圆角矩形,第二个图绘制是个BItmap,两者取交集,就实现了圆形图片的效果。
PorterDuff.Mode 16种效果图,如下。
最终实现:
参考
1.鸿神:http://blog.csdn.net/lmj623565791/article/details/24555655
2.https://blog.csdn.net/fhkatuz674/article/details/39271581
二、自定义view实现图片的裁剪
这个必须记录一下,为了这个坑,耗费了一下午的时间,一直达不到想要的效果,裁剪出来的图一直带着黑色框,究其原因,竟然是我无意识的把Bitmap的分辨率从Bitmap.Config.ARGB_8888手贱改成了Bitmap.Config.ARGB_565的原因。
android中图片是以bitmap形式存在的,那么bitmap所占内存,直接影响到了应用所占内存大小。
其中,A代表透明度;R代表红色;G代表绿色;B代表蓝色。
- ALPHA_8:表示8位Alpha位图,即A=8,一个像素点占用1个字节,它没有颜色,只有透明度
- ARGB_4444:表示16位ARGB位图,即A=4,R=4,G=4,B=4,一个像素点占4+4+4+4=16位,2个字节
- ARGB_8888:表示32位ARGB位图,即A=8,R=8,G=8,B=8,一个像素点占8+8+8+8=32位,4个字节
- RGB_565:表示16位RGB位图,即R=5,G=6,B=5,它没有透明度,一个像素点占5+6+5=16位,2个字节
另外, bitmap经compress后保存jpg,原透明部分会自动填充为黑色,png则保持原色。
1.准备图片2张
2.实现
主要代码如下:
mSrc为黑色图片,newBitmap为要裁剪的图片。
private Bitmap getImage(Bitmap bitmap, int width, int height) { Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); Bitmap target = mSrc.copy(Bitmap.Config.ARGB_8888, true); Canvas canvas = new Canvas(target); canvas.drawBitmap(mSrc,0,0,paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); Bitmap newBitmap = Bitmap.createScaledBitmap(bitmap,width,height,false); canvas.drawBitmap(newBitmap,0,0,paint); return target; }
完整代码:

public class ChannelViewWidget extends FrameLayout { private Context context; private int solidColor; private Bitmap mSrc; public ChannelViewWidget(Context context) { this(context,null); } public ChannelViewWidget(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.channelview); solidColor = typedArray.getColor(R.styleable.channelview_solidColor, getResources().getColor(android.R.color.transparent)); mSrc = BitmapFactory.decodeResource(getResources(),typedArray.getResourceId(R.styleable.channelview_src,R.drawable.ic_channel_icon_black)); } private Bitmap getImage(Bitmap bitmap, int width, int height) { Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); Bitmap target = mSrc.copy(Bitmap.Config.ARGB_8888, true); Canvas canvas = new Canvas(target); canvas.drawBitmap(mSrc,0,0,paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); Bitmap newBitmap = Bitmap.createScaledBitmap(bitmap,width,height,false); canvas.drawBitmap(newBitmap,0,0,paint); return target; } public void setData(final List<String> channels){ final ResizeOptions resizeOptions = new ResizeOptions((int)YTSizeUtil.Companion.dp2px(context,24),(int)YTSizeUtil.Companion.dp2px(context,24)); final List<Bitmap> bitmaps = new ArrayList<>(); Disposable subscribe = Observable.create(new ObservableOnSubscribe<String>() { @Override public void subscribe(ObservableEmitter<String> e) throws Exception { for (int i = 0; i < channels.size(); i++) { e.onNext(channels.get(i)); } } }).map(new Function<String, List<Bitmap>>() { @Override public List<Bitmap> apply(String s) throws Exception { DataSource<CloseableReference<CloseableImage>> dataSource = Fresco.getImagePipeline() .fetchDecodedImage(ImageRequestBuilder.newBuilderWithSource(Uri.parse(s)) .setResizeOptions(resizeOptions).build(), this); dataSource.subscribe(new BaseBitmapDataSubscriber() { @Override protected void onNewResultImpl(final Bitmap bitmap) { bitmaps.add(bitmap); } @Override protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) { } }, CallerThreadExecutor.getInstance()); return bitmaps; } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer<List<Bitmap>>() { @Override public void accept(List<Bitmap> list) throws Exception { if(list.size() != channels.size()) return; for (int i = 0; i < list.size(); i++) { addView(addChildView(list.get(i), i,list.size())); } } }, new Consumer<Throwable>() { @Override public void accept(Throwable throwable) throws Exception { } }); } private View addChildView(Bitmap bitmap, int index,int size) { View inflate = null; inflate= LayoutInflater.from(context).inflate(R.layout.exp_item_channel, this, false); SimpleDraweeView sdv_image = inflate.findViewById(R.id.sdv_channel_image); if (index == 0) { sdv_image.setImageBitmap(bitmap); } else { sdv_image.setImageBitmap(getImage(bitmap, (int) YTSizeUtil.Companion.dp2px(context, 24), (int) YTSizeUtil.Companion.dp2px(context, 24))); } ((LayoutParams) inflate.getLayoutParams()).rightMargin = (int) YTSizeUtil.Companion.dp2px(context, 20) * (size-index-1); return inflate; } }
实现效果:
图片压缩资料参考: