当paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));设置边框到圆形imageview时不起作用;

时间:2017-07-14 07:28:05

标签: android canvas imageview paint geometry

我想将边框设置为圆形图像视图,并且还希望图像视图位于圆圈内,所以下面是我的代码 -

public static Bitmap getRoundedRectBitmap(Bitmap bitmap, int pixels) {
        Bitmap result = null;
        try {
            result = Bitmap.createBitmap(pixels, pixels, Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(result);

            Paint paint = new Paint();
            Rect rect = new Rect(0, 0, pixels*2, pixels*2);

           // paint.setAntiAlias(true);
          //;  canvas.drawARGB(0, 0, 0, 0);

            paint.setStyle(Paint.Style.FILL);
            paint.setColor(Color.WHITE);
            canvas.drawCircle(pixels/2, pixels/2, pixels/2, paint);

            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeWidth(15);
            paint.setColor(Color.parseColor("#17B3F0"));
            canvas.drawCircle(pixels/2+0.7f, pixels/2+0.7f, pixels/2+0.1f, paint);


            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
            canvas.drawBitmap(bitmap, rect, rect, paint);

        } catch (NullPointerException e) {
        } catch (OutOfMemoryError o) {
        }
        return result;
    }

所以问题在于线 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

如果我正在评论此行,则会将所有属性添加到绘制对象中,但会使图像从圆圈中显示出来。 但我希望图像在圆圈内以及要设置的边框。 感谢任何帮助。谢谢。

从此处更新 -

我创建了一个自定义类MyCustomAdapter和Inside getView我正在设置imageView onStateChangeListener,如下所示 -

@覆盖     public View getView(int position,View convertView,ViewGroup parent){

        int type = getItemViewType(position);
        View view = inflater.inflate(type == List_Section ? R.layout.section : R.layout.listitem, parent, false);

        if (type == List_Section) {
            departments = ((TextView) view.findViewById(R.id.tv_li_section));
            departments.setText(list_complete_data.get(position).toString());
        } else {
            //StateListDrawable stateListDrawable = (StateListDrawable) view.getBackground();
          Emp_name = (TextView) view.findViewById(R.id.emp_name);
            Emp_number = (TextView) view.findViewById(R.id.emp_no);
            small_profile =(CircleImageView)view.findViewById(R.id.small_profile);
            Log.e(TAG,"small_profile====="+small_profile);
            Log.e(TAG,"inside getView=====");

           small_profile.setOnStateChangedListener(new OnStateChangeListener() {
                @Override
                public void onStateChanged(int state) {
                    Log.e(TAG,"onStateistener and  state=="+state+".,,,R.attr.state_on==="+R.attr.state_on+",,,R.attr.state_off=="+R.attr.state_off);
                    switch (state){
                        case R.attr.state_on :
                            small_profile.setBorderColor(Color.parseColor("#ffffff"));
                            break;
                        case R.attr.state_off:
                            small_profile.setBorderColor(Color.parseColor("#000000"));
                            break;
                    }
                }
            });

2 个答案:

答案 0 :(得分:1)

编辑:我已根据您的要求对代码进行了一些更改:

将以下界面添加到您的项目中:

public interface OnStateChangeListener {
    void onStateChanged(int state);
}

然后制作然后我在CircleImageView

中做了一些更改
public class CircleImageView extends ImageView implements View.OnTouchListener {

private static final int[] mStates = { R.attr.state_notset, R.attr.state_on, R.attr.state_off };
    private int mStateIndex = 0; // first state is "notset"

    private OnStateChangeListener mListener;
    private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;

    private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
    private static final int COLORDRAWABLE_DIMENSION = 2;

    private static final int DEFAULT_BORDER_WIDTH = 0;
    private static final int DEFAULT_BORDER_COLOR = Color.BLACK;
    private static final int DEFAULT_FILL_COLOR = Color.TRANSPARENT;
    private static final boolean DEFAULT_BORDER_OVERLAY = false;

    private final RectF mDrawableRect = new RectF();
    private final RectF mBorderRect = new RectF();

    private final Matrix mShaderMatrix = new Matrix();
    private final Paint mBitmapPaint = new Paint();
    private final Paint mBorderPaint = new Paint();
    private final Paint mFillPaint = new Paint();

    private int mBorderColor = DEFAULT_BORDER_COLOR;
    private int mBorderWidth = DEFAULT_BORDER_WIDTH;
    private int mFillColor = DEFAULT_FILL_COLOR;

    private Bitmap mBitmap;
    private BitmapShader mBitmapShader;
    private int mBitmapWidth;
    private int mBitmapHeight;

    private float mDrawableRadius;
    private float mBorderRadius;

    private ColorFilter mColorFilter;

    private boolean mReady;
    private boolean mSetupPending;
    private boolean mBorderOverlay;

    public CircleImageView(Context context) {
        super(context);

        init();
    }

    public CircleImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0);

        mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_civ_border_width, DEFAULT_BORDER_WIDTH);
        mBorderColor = a.getColor(R.styleable.CircleImageView_civ_border_color, DEFAULT_BORDER_COLOR);
        mBorderOverlay = a.getBoolean(R.styleable.CircleImageView_civ_border_overlay, DEFAULT_BORDER_OVERLAY);
        mFillColor = a.getColor(R.styleable.CircleImageView_civ_fill_color, DEFAULT_FILL_COLOR);

        a.recycle();

        init();
    }

    private void init() {
        super.setScaleType(SCALE_TYPE);
        mReady = true;

        if (mSetupPending) {
            setup();
            mSetupPending = false;
        }
    }

    @Override
    public ScaleType getScaleType() {
        return SCALE_TYPE;
    }

    @Override
    public void setScaleType(ScaleType scaleType) {
        if (scaleType != SCALE_TYPE) {
            throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType));
        }
    }

    @Override
    public void setAdjustViewBounds(boolean adjustViewBounds) {
        if (adjustViewBounds) {
            throw new IllegalArgumentException("adjustViewBounds not supported.");
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mBitmap == null) {
            return;
        }

        if (mFillColor != Color.TRANSPARENT) {
            canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, mDrawableRadius, mFillPaint);
        }
        canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, mDrawableRadius, mBitmapPaint);
        if (mBorderWidth != 0) {
            canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, mBorderRadius, mBorderPaint);
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        setup();
    }

    public int getBorderColor() {
        return mBorderColor;
    }

    public void setBorderColor(@ColorInt int borderColor) {
        if (borderColor == mBorderColor) {
            return;
        }

        mBorderColor = borderColor;
        mBorderPaint.setColor(mBorderColor);
        invalidate();
    }

    public void setBorderColorResource(@ColorRes int borderColorRes) {
        setBorderColor(getContext().getResources().getColor(borderColorRes));
    }

    public int getFillColor() {
        return mFillColor;
    }

    public void setFillColor(@ColorInt int fillColor) {
        if (fillColor == mFillColor) {
            return;
        }

        mFillColor = fillColor;
        mFillPaint.setColor(fillColor);
        invalidate();
    }

    public void setFillColorResource(@ColorRes int fillColorRes) {
        setFillColor(getContext().getResources().getColor(fillColorRes));
    }

    public int getBorderWidth() {
        return mBorderWidth;
    }

    public void setBorderWidth(int borderWidth) {
        if (borderWidth == mBorderWidth) {
            return;
        }

        mBorderWidth = borderWidth;
        setup();
    }

    public boolean isBorderOverlay() {
        return mBorderOverlay;
    }

    public void setBorderOverlay(boolean borderOverlay) {
        if (borderOverlay == mBorderOverlay) {
            return;
        }

        mBorderOverlay = borderOverlay;
        setup();
    }

    @Override
    public void setImageBitmap(Bitmap bm) {
        super.setImageBitmap(bm);
        mBitmap = bm;
        setup();
    }

    @Override
    public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        mBitmap = getBitmapFromDrawable(drawable);
        setup();
    }

    @Override
    public void setImageResource(@DrawableRes int resId) {
        super.setImageResource(resId);
        mBitmap = getBitmapFromDrawable(getDrawable());
        setup();
    }

    @Override
    public void setImageURI(Uri uri) {
        super.setImageURI(uri);
        mBitmap = uri != null ? getBitmapFromDrawable(getDrawable()) : null;
        setup();
    }

    @Override
    public void setColorFilter(ColorFilter cf) {
        if (cf == mColorFilter) {
            return;
        }

        mColorFilter = cf;
        applyColorFilter();
        invalidate();
    }

    @Override
    public ColorFilter getColorFilter() {
        return mColorFilter;
    }

    private void applyColorFilter() {
        if (mBitmapPaint != null) {
            mBitmapPaint.setColorFilter(mColorFilter);
        }
    }

    private Bitmap getBitmapFromDrawable(Drawable drawable) {
        if (drawable == null) {
            return null;
        }

        if (drawable instanceof BitmapDrawable) {
            return ((BitmapDrawable) drawable).getBitmap();
        }

        try {
            Bitmap bitmap;

            if (drawable instanceof ColorDrawable) {
                bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);
            } else {
                bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);
            }

            Canvas canvas = new Canvas(bitmap);
            drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
            drawable.draw(canvas);
            return bitmap;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    private void setup() {
        if (!mReady) {
            mSetupPending = true;
            return;
        }

        if (getWidth() == 0 && getHeight() == 0) {
            return;
        }

        if (mBitmap == null) {
            invalidate();
            return;
        }

        mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

        mBitmapPaint.setAntiAlias(true);
        mBitmapPaint.setShader(mBitmapShader);

        mBorderPaint.setStyle(Paint.Style.STROKE);
        mBorderPaint.setAntiAlias(true);
        mBorderPaint.setColor(mBorderColor);
        mBorderPaint.setStrokeWidth(mBorderWidth);

        mFillPaint.setStyle(Paint.Style.FILL);
        mFillPaint.setAntiAlias(true);
        mFillPaint.setColor(mFillColor);

        mBitmapHeight = mBitmap.getHeight();
        mBitmapWidth = mBitmap.getWidth();

        mBorderRect.set(0, 0, getWidth(), getHeight());
        mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2.0f, (mBorderRect.width() - mBorderWidth) / 2.0f);

        mDrawableRect.set(mBorderRect);
        if (!mBorderOverlay) {
            mDrawableRect.inset(mBorderWidth, mBorderWidth);
        }
        mDrawableRadius = Math.min(mDrawableRect.height() / 2.0f, mDrawableRect.width() / 2.0f);

        applyColorFilter();
        updateShaderMatrix();
        invalidate();
    }

    private void updateShaderMatrix() {
        float scale;
        float dx = 0;
        float dy = 0;

        mShaderMatrix.set(null);

        if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
            scale = mDrawableRect.height() / (float) mBitmapHeight;
            dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
        } else {
            scale = mDrawableRect.width() / (float) mBitmapWidth;
            dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
        }

        mShaderMatrix.setScale(scale, scale);
        mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top);

        mBitmapShader.setLocalMatrix(mShaderMatrix);
    }

    @Override
    public int[] onCreateDrawableState(int extraSpace) {
        final int[] drawableState = super.onCreateDrawableState(extraSpace+1);

        int [] state = { mStates[mStateIndex] };

        mergeDrawableStates(drawableState, state);

        return drawableState;
    }

    public void setOnStateChangedListener(OnStateChangeListener l) {
        this.mListener = l;
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.e("STATETOUCH", "onTouch: down");
                mStateIndex = 1;
                if(mListener != null) mListener.onStateChanged(mStates[1]);
                return true;
            case MotionEvent.ACTION_UP:
                Log.e("STATETOUCH", "onTouch: up");
                mStateIndex = 2;
                if(mListener != null) mListener.onStateChanged(mStates[2]);
                return false;
        }
        return false;
    }
 }
attrs.xml中的

编辑

,这在attrs.xml

<declare-styleable name="CircleImageView">
        <attr name="civ_border_width" format="dimension" />
        <attr name="civ_border_color" format="color" />
        <attr name="civ_border_overlay" format="boolean" />
        <attr name="civ_fill_color" format="color" />
        <attr name="state_on" format="boolean" />
        <attr name="state_off" format="boolean" />
    </declare-styleable>

并在您的代码中使用它:

<com.yourpackagename.CircleImageView
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:id="@+id/img"
        app:civ_border_width="1dp"
        app:civ_border_color="#000"
        android:src="@drawable/profile_pic"/>

然后在您的代码中执行以下操作:

yourImageView.setOnStateChangedListener(new OnStateChangeListener() {
            @Override
            public void onStateChanged(int state) {
                switch (state){
                    case R.attr.state_on:
                        yourImageView.setBorderColor(Color.parseColor("#00ff00"));
                        break;
                    case R.attr.state_off:
                        yourImageView.setBorderColor(Color.parseColor("#ff00ff"));
                    //do anything you would do after onclick of this imageview here, like open a new activity.
                        break;
                }

                Log.e("STATECHANGE", "State changed to: " + context.getResources().getResourceEntryName(state));
            }
        });

参考:https://stackoverflow.com/a/21969864/2251837

works fine for me

正如您所看到的,此代码对我来说很好。你可以发布你的代码,你是怎么做到的,然后我可以帮忙吗?

编辑:这是您需要在getView()方法中更改的内容:

view.setOnTouchListener(new View.OnTouchListener() { // here view is this view : View view = inflater.inflate(type == List_Section ? R.layout.section : R.layout.listitem, parent, false);
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                small_profile.dispatchTouchEvent(event);
                return false;
            }
        });

答案 1 :(得分:0)

您需要在此处绘制2位图以激活Xfermode:

private Bitmap maskingImage(Bitmap s1, Bitmap s2) {
    Bitmap result = Bitmap.createBitmap(s2.getWidth(), s2.getHeight(), Bitmap.Config.ARGB_8888);
    Canvas mCanvas = new Canvas(result);
    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
    mCanvas.drawBitmap(s1, 0, 0, null);
    mCanvas.drawBitmap(s2, 0, 0, paint);
    paint.setXfermode(null);
    return result;
}

s2是你的圈子,s1是你的形象。如果要更改为Mode.SRC_IN,只需交换s1和s2参数位置