NiceImageView icon indicating copy to clipboard operation
NiceImageView copied to clipboard

android 9.0圆形 带边框 图片内容 超出圆形边框

Open Marysays opened this issue 6 years ago • 15 comments

1536169312264 已经cover src

Marysays avatar Sep 05 '18 17:09 Marysays

同样的问题,期待up修复

image

   <com.othershe.library.NiceImageView
                android:layout_width="@dimen/dp_113"
                android:layout_height="@dimen/dp_113"
                android:layout_marginTop="@dimen/dp_12"
                android:src="@mipmap/avatar_test"
                app:border_width="5dp"
                app:border_color="@color/colorPrimary"
                app:is_circle="true" />



   <com.othershe.library.NiceImageView
                android:layout_width="@dimen/dp_113"
                android:layout_height="@dimen/dp_113"
                android:layout_marginTop="@dimen/dp_12"
                android:src="@mipmap/avatar_test"
                app:border_width="5dp"
                android:scaleType="centerCrop"
                app:border_color="@color/colorPrimary"
                app:corner_radius="@dimen/dp_10" />

fairytale110 avatar Sep 07 '18 09:09 fairytale110

同样遇到了这个问题。。

liangpengfei avatar Nov 27 '18 14:11 liangpengfei

大佬 这个什么时候能修 都两个月了。。。。。。。。。。

Marysays avatar Nov 29 '18 09:11 Marysays

8.1到9.0的设备存在兼容性的问题,问题已经定位,只是目前缺少测试设备

shehuan avatar Nov 29 '18 10:11 shehuan

你as直接载个 9.0的虚拟机 我也是在虚拟机上面发现的bug

Marysays avatar Nov 29 '18 10:11 Marysays

能不能定位的问题发一下吧,我先在代码里面自己改一下

Gerry0927 avatar Dec 03 '18 02:12 Gerry0927

作者更新太慢了。。Bug只能自己动手修了(有没有影响到其他功能需要大家再认真测下 我试是没问题的~) ==========================分割线============================== 一、问题出在哪? 控件用到了 Xfermode这个东西,我试了下。 1、先画一个circle(非bitmap),然后setXfermode 为Src_In,再画一个bitmap(图片的),正常显示。 2、先画一个bitmap(图片的),然后setXfermode 为Dsr_In,再画circle。异常。(大概看下来代码 作者应该用的这一种画法)

第一种:先画circle 在canvas那层,再画Bitmap新一层,中间Xfermode 第二种: 先画bitmap一层,再画circle还是原来那层 中间Xfermode =============================上代码====================== package com.othershe.library;

import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.RectF; import android.graphics.Xfermode; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.support.annotation.ColorInt; import android.support.annotation.Nullable; import android.support.v7.widget.AppCompatImageView; import android.util.AttributeSet;

public class NiceImageView extends AppCompatImageView { private Context context; private boolean isCircle; // 是否显示为圆形,如果为圆形则设置的corner无效 private boolean isCoverSrc; // border、inner_border是否覆盖图片 private int borderWidth; // 边框宽度 private int borderColor = Color.WHITE; // 边框颜色 private int innerBorderWidth; // 内层边框宽度 private int innerBorderColor = Color.WHITE; // 内层边框充色

private int cornerRadius; // 统一设置圆角半径,优先级高于单独设置每个角的半径
private int cornerTopLeftRadius; // 左上角圆角半径
private int cornerTopRightRadius; // 右上角圆角半径
private int cornerBottomLeftRadius; // 左下角圆角半径
private int cornerBottomRightRadius; // 右下角圆角半径

private int maskColor; // 遮罩颜色

private Xfermode xfermode;

private int width;
private int height;
private float radius;

private float[] borderRadii;
private float[] srcRadii;

private RectF srcRectF; // 图片占的矩形区域
private RectF borderRectF; // 边框的矩形区域

private Path path = new Path();
private Paint paint = new Paint();

public NiceImageView(Context context) {
    this(context, null);
}

public NiceImageView(Context context, @Nullable AttributeSet attrs) {
    this(context, attrs, 0);
}

public NiceImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);

    this.context = context;

    TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.NiceImageView, 0, 0);
    for (int i = 0; i < ta.getIndexCount(); i++) {
        int attr = ta.getIndex(i);
        if (attr == R.styleable.NiceImageView_is_cover_src) {
            isCoverSrc = ta.getBoolean(attr, isCoverSrc);
        } else if (attr == R.styleable.NiceImageView_is_circle) {
            isCircle = ta.getBoolean(attr, isCircle);
        } else if (attr == R.styleable.NiceImageView_border_width) {
            borderWidth = ta.getDimensionPixelSize(attr, borderWidth);
        } else if (attr == R.styleable.NiceImageView_border_color) {
            borderColor = ta.getColor(attr, borderColor);
        } else if (attr == R.styleable.NiceImageView_inner_border_width) {
            innerBorderWidth = ta.getDimensionPixelSize(attr, innerBorderWidth);
        } else if (attr == R.styleable.NiceImageView_inner_border_color) {
            innerBorderColor = ta.getColor(attr, innerBorderColor);
        } else if (attr == R.styleable.NiceImageView_corner_radius) {
            cornerRadius = ta.getDimensionPixelSize(attr, cornerRadius);
        } else if (attr == R.styleable.NiceImageView_corner_top_left_radius) {
            cornerTopLeftRadius = ta.getDimensionPixelSize(attr, cornerTopLeftRadius);
        } else if (attr == R.styleable.NiceImageView_corner_top_right_radius) {
            cornerTopRightRadius = ta.getDimensionPixelSize(attr, cornerTopRightRadius);
        } else if (attr == R.styleable.NiceImageView_corner_bottom_left_radius) {
            cornerBottomLeftRadius = ta.getDimensionPixelSize(attr, cornerBottomLeftRadius);
        } else if (attr == R.styleable.NiceImageView_corner_bottom_right_radius) {
            cornerBottomRightRadius = ta.getDimensionPixelSize(attr, cornerBottomRightRadius);
        } else if (attr == R.styleable.NiceImageView_mask_color) {
            maskColor = ta.getColor(attr, maskColor);
        }
    }
    ta.recycle();

    borderRadii = new float[8];
    srcRadii = new float[8];

    borderRectF = new RectF();
    srcRectF = new RectF();

    xfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);

    calculateRadii();
    clearInnerBorderWidth();
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    width = w;
    height = h;

    initBorderRectF();
    initSrcRectF();
}

//替换掉NICEIAMGE类中的这个方法就行了
@Override
protected void onDraw(Canvas canvas) {

// 使用图形混合模式来显示指定区域的图片 canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG); Drawable drawable = getDrawable(); if (drawable == null) { super.onDraw(canvas); return; } paint.reset(); path.reset(); if (!isCoverSrc) { float sx = 1.0f * (width - 2 * borderWidth - 2 * innerBorderWidth) / width; float sy = 1.0f * (height - 2 * borderWidth - 2 * innerBorderWidth) / height; // 缩小画布,使图片内容不被border、padding覆盖 canvas.scale(sx, sy, width / 2.0f, height / 2.0f); }

    if (isCircle) {
        path.addCircle(width / 2.0f, height / 2.0f, radius, Path.Direction.CCW);
    } else {
        path.addRoundRect(srcRectF, srcRadii, Path.Direction.CCW);
    }

    paint.setAntiAlias(true);
    paint.setStyle(Paint.Style.FILL);

    canvas.drawPath(path, paint);
    paint.setXfermode(xfermode);


    canvas.drawBitmap(zoomDrawable(drawable), 0, 0, paint);
    paint.setXfermode(null);

    // 绘制遮罩
    if (maskColor != 0) {
        paint.setColor(maskColor);
        canvas.drawPath(path, paint);
    }
    // 恢复画布
    canvas.restore();
    // 绘制边框
    drawBorders(canvas);
}

private void drawBorders(Canvas canvas) {
    if (isCircle) {
        if (borderWidth > 0) {
            drawCircleBorder(canvas, borderWidth, borderColor, radius - borderWidth / 2.0f);
        }
        if (innerBorderWidth > 0) {
            drawCircleBorder(canvas, innerBorderWidth, innerBorderColor, radius - borderWidth - innerBorderWidth / 2.0f);
        }
    } else {
        if (borderWidth > 0) {
            drawRectFBorder(canvas, borderWidth, borderColor, borderRectF, borderRadii);
        }
    }
}

private void drawCircleBorder(Canvas canvas, int borderWidth, int borderColor, float radius) {
    initBorderPaint(borderWidth, borderColor);
    path.addCircle(width / 2.0f, height / 2.0f, radius, Path.Direction.CCW);
    canvas.drawPath(path, paint);
}

private void drawRectFBorder(Canvas canvas, int borderWidth, int borderColor, RectF rectF, float[] radii) {
    initBorderPaint(borderWidth, borderColor);
    path.addRoundRect(rectF, radii, Path.Direction.CCW);
    canvas.drawPath(path, paint);
}

private void initBorderPaint(int borderWidth, int borderColor) {
    path.reset();
    paint.setStrokeWidth(borderWidth);
    paint.setColor(borderColor);
    paint.setStyle(Paint.Style.STROKE);
}

/**
 * 计算外边框的RectF
 */
private void initBorderRectF() {
    if (!isCircle) {
        borderRectF.set(borderWidth / 2.0f, borderWidth / 2.0f, width - borderWidth / 2.0f, height - borderWidth / 2.0f);
    }
}

/**
 * 计算图片原始区域的RectF
 */
private void initSrcRectF() {
    if (isCircle) {
        radius = Math.min(width, height) / 2.0f;
        srcRectF.set(width / 2.0f - radius, height / 2.0f - radius, width / 2.0f + radius, height / 2.0f + radius);
    } else {
        srcRectF.set(0, 0, width, height);
        if (isCoverSrc) {
            srcRectF = borderRectF;
        }
    }
}

/**
 * 计算RectF的圆角半径
 */
private void calculateRadii() {
    if (isCircle) {
        return;
    }
    if (cornerRadius > 0) {
        for (int i = 0; i < borderRadii.length; i++) {
            borderRadii[i] = cornerRadius;
            srcRadii[i] = cornerRadius - borderWidth / 2.0f;
        }
    } else {
        borderRadii[0] = borderRadii[1] = cornerTopLeftRadius;
        borderRadii[2] = borderRadii[3] = cornerTopRightRadius;
        borderRadii[4] = borderRadii[5] = cornerBottomRightRadius;
        borderRadii[6] = borderRadii[7] = cornerBottomLeftRadius;

        srcRadii[0] = srcRadii[1] = cornerTopLeftRadius - borderWidth / 2.0f;
        srcRadii[2] = srcRadii[3] = cornerTopRightRadius - borderWidth / 2.0f;
        srcRadii[4] = srcRadii[5] = cornerBottomRightRadius - borderWidth / 2.0f;
        srcRadii[6] = srcRadii[7] = cornerBottomLeftRadius - borderWidth / 2.0f;
    }
}

private void calculateRadiiAndRectF(boolean reset) {
    if (reset) {
        cornerRadius = 0;
    }
    calculateRadii();
    initBorderRectF();
    invalidate();
}

/**
 * 目前圆角矩形情况下不支持inner_border,需要将其置0
 */
private void clearInnerBorderWidth() {
    if (!isCircle) {
        this.innerBorderWidth = 0;
    }
}

public void isCoverSrc(boolean isCoverSrc) {
    this.isCoverSrc = isCoverSrc;
    initSrcRectF();
    invalidate();
}

public void isCircle(boolean isCircle) {
    this.isCircle = isCircle;
    clearInnerBorderWidth();
    initSrcRectF();
    invalidate();
}

public void setBorderWidth(int borderWidth) {
    this.borderWidth = Utils.dp2px(context, borderWidth);
    calculateRadiiAndRectF(false);
}

public void setBorderColor(@ColorInt int borderColor) {
    this.borderColor = borderColor;
    invalidate();
}

public void setInnerBorderWidth(int innerBorderWidth) {
    this.innerBorderWidth = Utils.dp2px(context, innerBorderWidth);
    clearInnerBorderWidth();
    invalidate();
}

public void setInnerBorderColor(@ColorInt int innerBorderColor) {
    this.innerBorderColor = innerBorderColor;
    invalidate();
}

public void setCornerRadius(int cornerRadius) {
    this.cornerRadius = Utils.dp2px(context, cornerRadius);
    calculateRadiiAndRectF(false);
}

public void setCornerTopLeftRadius(int cornerTopLeftRadius) {
    this.cornerTopLeftRadius = Utils.dp2px(context, cornerTopLeftRadius);
    calculateRadiiAndRectF(true);
}

public void setCornerTopRightRadius(int cornerTopRightRadius) {
    this.cornerTopRightRadius = Utils.dp2px(context, cornerTopRightRadius);
    calculateRadiiAndRectF(true);
}

public void setCornerBottomLeftRadius(int cornerBottomLeftRadius) {
    this.cornerBottomLeftRadius = Utils.dp2px(context, cornerBottomLeftRadius);
    calculateRadiiAndRectF(true);
}

public void setCornerBottomRightRadius(int cornerBottomRightRadius) {
    this.cornerBottomRightRadius = Utils.dp2px(context, cornerBottomRightRadius);
    calculateRadiiAndRectF(true);
}

public void setMaskColor(@ColorInt int maskColor) {
    this.maskColor = maskColor;
    invalidate();
}

private Bitmap drawableToBitamp(Drawable drawable) {
    if (drawable instanceof BitmapDrawable) {
        BitmapDrawable bd = (BitmapDrawable) drawable;
        return bd.getBitmap();
    }
    // 设置为颜色时,获取的drawable宽高会有问题,所有当为颜色时候获取控件的宽高
    int w = drawable.getIntrinsicWidth() <= 0 ? getWidth() : drawable.getIntrinsicWidth();
    int h = drawable.getIntrinsicHeight() <= 0 ? getHeight() : drawable.getIntrinsicHeight();
    Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    drawable.setBounds(0, 0, w, h);
    drawable.draw(canvas);
    return bitmap;
}

private Bitmap zoomDrawable(Drawable drawable) {
    int width = drawable.getIntrinsicWidth();
    int height = drawable.getIntrinsicHeight();
    Bitmap oldbmp = drawableToBitamp(drawable);
    Matrix matrix = new Matrix();
    float scaleWidth = ((float) getWidth() / width);
    float scaleHeight = ((float) getHeight() / height);
    matrix.postScale(scaleWidth, scaleHeight);
    Bitmap newbmp = Bitmap.createBitmap(oldbmp, 0, 0, width, height,
            matrix, true);
    return newbmp;
}

} ===========================上面为整个类===============================

Marysays avatar Dec 05 '18 09:12 Marysays

问题已修复

shehuan avatar Dec 08 '18 06:12 shehuan

诺基亚X6上还是发现同样的问题 版本1.0.5

1

lvyandev avatar Dec 10 '18 03:12 lvyandev

按照我那个思路看下 问题是出在这

Marysays avatar Dec 10 '18 11:12 Marysays

还有个问题就是 9.0系统中 设置了圆角度,但是在界面中展示的没有效果

Gerry0927 avatar Dec 13 '18 01:12 Gerry0927

9.0系统 列表中,来回滑动 圆形 有时候可以正常显示,有时候显示矩形。是不是drawCircleBorder方法里面drawPath时 也要判断if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) 进行适配

Maheaven avatar Dec 13 '18 13:12 Maheaven

你好,华为手机9.0系统 设置了圆角度不生效,请问下是什么原因

idic779 avatar Mar 23 '19 16:03 idic779

小米8,9.0系统仍然存在这个问题

wsfbailebai avatar Apr 15 '19 08:04 wsfbailebai

super.onDraw(canvas); paint.reset(); path.reset(); 后面增加这句srcRectF .reset(); 试下

clgg avatar Oct 23 '19 10:10 clgg