androidandroid-viewandroid-custom-viewporter-duffandroid-paint

Display TextView with 2 separate colors using mask


I am trying to achieve an effect similar to this one:

enter image description here

What I am doing now:

public MaskedTextView(Context context, AttributeSet attrs) {
    super(context, attrs);

    p = new Paint(Paint.ANTI_ALIAS_FLAG);
    p.setTextSize(25);
    p.setColor(Color.GREEN);

    pReplace = new Paint(p);
    pReplace.setColor(Color.BLUE);
    pReplace.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER));

    pMask = new Paint();
    int lightGradientColor = getResources().getColor(R.color.dailyGoalLowLight);
    int darkGradientColor = getResources().getColor(R.color.dailyGoalLowDark);
    Shader shader = new LinearGradient(0, 0, 150, 0, lightGradientColor, darkGradientColor, Shader.TileMode.CLAMP);
    pMask.setShader(shader);
    pMask.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
@Override
public void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.save();
    if (!Utils.isEmpty(sText)) {
        canvas.drawText(sText, 150, getHeight() / 2, p);
        canvas.drawRect(0, 0, 180, getHeight(), pMask);
        canvas.drawText(sText, 150, getHeight()/2, pReplace);
    }
    canvas.restore();
}

This results in:

enter image description here

Close, the problem here is the horizontal linear gradient does not show up when setting the pMask.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));.

If I comment out that line I get the following result:

enter image description here

Close again, but now the linear gradient completely covers the text. Can someone help me with what I'm missing here. Is there a better way to achieve this effect?


Solution

  • PorterDuff.Mode.SRC_IN maybe helps. And setLayerType(View.LAYER_TYPE_SOFTWARE, null); should be called to work with SRC_IN.

    public class MaskedTextView extends View {
    
        private final Paint pLeftBg;
        private final Paint pText;
        private final Paint pRightMask;
        private String mText = "web";
    
        public MaskedTextView(Context context, AttributeSet attrs) {
            super(context, attrs);
    
            pLeftBg = new Paint();
            int lightGradientColor = ContextCompat.getColor(getContext(), R.color.dailyGoalLowLight);
            int darkGradientColor = ContextCompat.getColor(getContext(), R.color.dailyGoalLowDark);
            Shader shader = new LinearGradient(0, 0, 150, 0, lightGradientColor, darkGradientColor, Shader.TileMode.CLAMP);
            pLeftBg.setShader(shader);
    
            pText = new Paint(Paint.ANTI_ALIAS_FLAG);
            pText.setTextSize(50);
            pText.setColor(Color.WHITE);
    
            pRightMask = new Paint();
            pRightMask.setColor(ContextCompat.getColor(getContext(), R.color.dailyGoalLowLight));
            pRightMask.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
    
            setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        }
    
        @Override
        public void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            canvas.save();
            canvas.drawRect(0, 0, 100, getHeight(), pLeftBg);
            canvas.drawText(mText, 50, getHeight() / 2, pText);
            canvas.drawRect(100, 0, getWidth(), getHeight(), pRightMask);
            canvas.restore();
        }
    }
    

    Output:

    enter image description here