Tears_fg

导航

自定义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.实现 

attr文件中定义属性:

    <declare-styleable name="channelview">
        <attr name="solidColor" format="reference|color" />
        <attr name="src" format="reference" />
    </declare-styleable>

 

主要代码如下:

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

完整代码:

package com.ingtube.common.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;

import com.bumptech.glide.Glide;
import com.ingtube.common.R;
import com.ingtube.common.util.YTSizeUtil;

import java.util.ArrayList;
import java.util.List;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;

import static android.graphics.Bitmap.Config.ARGB_8888;

public class ChannelViewWidget extends FrameLayout {
    private Context context;
    private int solidColor;
    private static 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);
        paint.setXfermode(null);
        return target;
    }

    public void setData(final List<String> channels){
        if(channels == null || channels.size() == 0) return;
        Disposable subscribe = Observable.create(new ObservableOnSubscribe<List<Bitmap>>() {
            @Override
            public void subscribe(final ObservableEmitter<List<Bitmap>> e) throws Exception {
                List<Bitmap> bitmaps = new ArrayList<>();
                for (int i = 0; i < channels.size(); i++) {
                    Bitmap bitmap = Glide.with(context).asBitmap().load(channels.get(i)).submit((int)YTSizeUtil.Companion.dp2px(context,24),(int)YTSizeUtil.Companion.dp2px(context,24)).get();
                    bitmaps.add(i == 0?bitmap.copy(ARGB_8888,false):getImage(bitmap, (int) YTSizeUtil.Companion.dp2px(context, 24), (int) YTSizeUtil.Companion.dp2px(context, 24)));
                }
                e.onNext(bitmaps);
                e.onComplete();
            }
        })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<List<Bitmap>>() {
                    @Override
                    public void accept(List<Bitmap> bitmaps) throws Exception {
                        if (bitmaps.size() == channels.size()) {
                            for (int i = 0; i < bitmaps.size(); i++) {
                                addView(addChildView(bitmaps.get(i), i, bitmaps.size()));
                            }
                        }
                    }

                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        throwable.printStackTrace();
                    }
                });


    }

    private View addChildView(Bitmap bitmap, int index,int size) {
        View inflate = null;
        inflate= LayoutInflater.from(context).inflate(R.layout.exp_item_channel, this, false);
        ImageView ivChannel = inflate.findViewById(R.id.iv_channel_image);
        Glide.with(context).asBitmap().load(bitmap).circleCrop().into(ivChannel);
        ((LayoutParams) inflate.getLayoutParams()).rightMargin = (int) YTSizeUtil.Companion.dp2px(context, 20) * (size-index-1);

        return inflate;
    }
}
ChannelViewWidget

实现效果:

 

 

 

图片压缩资料参考:

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

 

posted on 2019-06-25 15:44  Tears_fg  阅读(2176)  评论(0编辑  收藏  举报