自定義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