自定义View实现圆角化/自定义view实现图片的裁剪


一、自定义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;
    }
}
View Code

实现效果:

 

 

 

图片压缩资料参考:

1.bitmap的六种压缩方式,Android图片压缩

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM