【问题标题】:PorterDuff masking leaves opaque black backgroundPorterDuff 掩蔽叶不透明黑色背景
【发布时间】:2016-06-03 23:32:37
【问题描述】:

我正在尝试使用定义为九个补丁的掩码来掩码 FrameLayout。然而,虽然它在 5.0+ 的旧版本(例如 4.4.4)上运行良好,但补丁留下了不透明的黑色背景。除了在渲染到屏幕或恢复到软件层之前绘制到屏幕外位图之外,还有什么办法可以避免这种情况?

public class MaskedLayout extends FrameLayout {

    private final static PorterDuffXfermode DST_IN = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
    private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private NinePatchDrawable mMask;

    private boolean mShowTail = true;
    private boolean mReverseLayout;

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

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

    public ChatBubbleLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setWillNotDraw(false);
        setLayerType(LAYER_TYPE_HARDWARE, mPaint);

        mMask = createMask(R.drawable.mask);
    }

    private NinePatchDrawable createMask(@DrawableRes int res) {
        final Bitmap maskBitmap = BitmapFactory.decodeResource(getResources(), res);
        final NinePatch patch = new NinePatch(maskBitmap, maskBitmap.getNinePatchChunk(), "Mask");
        return new NinePatchDrawable(getResources(), patch);
    }

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

        if (w != oldw || h != oldh) {
            mMask.setBounds(0, 0, w, h);
        }
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        mMask.getPaint().setXfermode(DST_IN);
        mMask.draw(canvas);
    }
}

【问题讨论】:

    标签: android android-canvas android-custom-view mask porter-duff


    【解决方案1】:

    试试这个:

    public class MaskedLayout extends FrameLayout {
    
        private NinePatchDrawable mMask;
    
        public MaskedLayout(Context context) {
            this(context, null);
        }
    
        public MaskedLayout(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public MaskedLayout(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            mMask = (NinePatchDrawable) getResources().getDrawable(R.drawable.mask);
            mMask.getPaint().setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            mMask.setBounds(0, 0, w, h);
        }
    
        @Override
        protected void dispatchDraw(Canvas canvas) {
            canvas.saveLayer(null, null, Canvas.ALL_SAVE_FLAG);
            super.dispatchDraw(canvas);
            mMask.draw(canvas);
            canvas.restore();
        }
    }
    

    【讨论】:

    • 如果你想让任何Drawable“屏蔽”你的FrameLayout,你需要另一个“层”(saveLayer()),因为无法访问Drawables Paint对象
    • 谢谢,我很快就会试一试。使用 saveLayer 会在视图渲染上产生性能成本吗?你知道为什么代码可以在 5.0 而不是 4.x 上运行吗?
    • 不应该有任何重大影响,例如在 v4 之前的设备上,它用于 alpha 动画,以 20+ fps 调用,而这些设备不是速度守护进程,我不知道为什么它在 4.4 上不起作用
    • 抱歉耽搁了,周末没机会试一试。它似乎适用于 4.4.4,但现在我有一个奇怪的问题,即 MaskedLayout 的背景颜色被绘制来代替遮罩透明度
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-22
    • 2012-06-26
    • 2015-07-04
    • 2013-11-25
    • 2015-04-20
    • 1970-01-01
    相关资源
    最近更新 更多