使用 TextView 清除视图 canvas

Clear a views canvas with a TextView

我正在努力实现一种视觉效果,如果我能做出来,那将看起来棒极了!我正在执行的应用程序登录如下所示:

请记住,背景图像是一个动画,从该图像到另一个图像会略微过渡。

我想要的是让应用程序的标题 "Akrasia" 透明,但透明意味着您可以通过标题字母看到背景中的图像,这意味着我必须以某种方式覆盖 onDraw 包含此表单的 RelativeLayout 方法。我试图这样做,但我得到的唯一结果是错误。也许我在 TextViewRelativeLayout 中尝试覆盖 onDraw 方法是错误的,也许有最简单的方法来做到这一点。你怎么认为?或者可能无法达到这种效果?

更新:

它应该是这样的。

我还尝试制作一个从 TextView 扩展的自定义视图,它有一个方法 setBackgroundView 将视图实例存储到一个字段中。后来在 onDraw 方法上,我设法从背景图像中获取了位图。但我不知道如何使用 canvas.

绘制它

更新: 我让它工作!现在我只需要通过背景的可绘制对象更改 blue-like 背景。

观点:

final public class SeeThroughTextView extends TextView
{
    Bitmap mMaskBitmap;
    Canvas mMaskCanvas;
    Paint mPaint;

    Drawable mBackground;
    Bitmap mBackgroundBitmap;
    Canvas mBackgroundCanvas;
    boolean mSetBoundsOnSizeAvailable = false;

    public SeeThroughTextView(Context context)
    {
        super(context);
        init();
    }

    private void init() {
        mPaint = new Paint();
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
    }

    public SeeThroughTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public SeeThroughTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }



    @Override
    @Deprecated
    public void setBackgroundDrawable(Drawable bg)
    {
        mBackground = bg;
        int w = bg.getIntrinsicWidth();
        int h = bg.getIntrinsicHeight();

        // Drawable has no dimensions, retrieve View's dimensions
        if (w == -1 || h == -1)
        {
            w = getWidth();
            h = getHeight();
        }

        // Layout has not run
        if (w == 0 || h == 0)
        {
            mSetBoundsOnSizeAvailable = true;
            return;
        }

        mBackground.setBounds(0, 0, w, h);
        invalidate();
    }



    @Override
    public void setBackgroundColor(int color)
    {
        setBackgroundDrawable(new ColorDrawable(color));
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh)
    {
        super.onSizeChanged(w, h, oldw, oldh);
        mBackgroundBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        mBackgroundCanvas = new Canvas(mBackgroundBitmap);
        mMaskBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        mMaskCanvas = new Canvas(mMaskBitmap);

        if (mSetBoundsOnSizeAvailable)
        {
            mBackground.setBounds(0, 0, w, h);
            mSetBoundsOnSizeAvailable = false;
        }
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        // Draw background
        mBackground.draw(mBackgroundCanvas);

        // Draw mask
        mMaskCanvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR);
        super.onDraw(mMaskCanvas);

        mBackgroundCanvas.drawBitmap(mMaskBitmap, 0.f, 0.f, mPaint);
        canvas.drawBitmap(mBackgroundBitmap, 0.f, 0.f, null);
    }
}

在我的片段中我有这个因为背景中的动画:

vBackground.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                vTitle.setBackgroundDrawable(new BitmapDrawable(vBackground.getDrawingCache()));
                vTitle.invalidate();
            }
        });

在您的 res/values/colors.xml 文件中指定一种新颜色(如果不存在则创建一个),该文件可能如下所示:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="ltGray">#33999999</color>
</resources>

其中前两个数字是透明度(00 - 完全透明,FF - 完全不透明)。

然后只需在该布局的 xml 中将所需 TextView 的文本颜色设置为 @color/ltGray,或者转到 tvTitle.setTextColor(getResources().getColor(R.color.ltGray)) 在实例化 TextView.

之后

搞定了!

观点:

final public class SeeThroughTextView extends TextView
{
    Bitmap mMaskBitmap;
    Canvas mMaskCanvas;
    Paint mPaint;

    Drawable mBackground;
    Bitmap mBackgroundBitmap;
    Canvas mBackgroundCanvas;
    boolean mSetBoundsOnSizeAvailable = false;

    public SeeThroughTextView(Context context)
    {
        super(context);
        init();
    }

    private void init() {
        Typeface myTypeface = Typeface.createFromAsset(getContext().getAssets(), "fonts/gillsans.ttf");
        setTypeface(myTypeface);
        mPaint = new Paint();
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
    }

    public SeeThroughTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public SeeThroughTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }



    @Override
    @Deprecated
    public void setBackgroundDrawable(Drawable bg)
    {
        mBackground = bg;
        int w = bg.getIntrinsicWidth();
        int h = bg.getIntrinsicHeight();

        // Drawable has no dimensions, retrieve View's dimensions
        if (w == -1 || h == -1)
        {
            w = getWidth();
            h = getHeight();
        }

        // Layout has not run
        if (w == 0 || h == 0)
        {
            mSetBoundsOnSizeAvailable = true;
            return;
        }

        mBackground.setBounds(0, 0, w, h);
        invalidate();
    }



    @Override
    public void setBackgroundColor(int color)
    {
        setBackgroundDrawable(new ColorDrawable(color));
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh)
    {
        super.onSizeChanged(w, h, oldw, oldh);
        mBackgroundBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        mBackgroundCanvas = new Canvas(mBackgroundBitmap);
        mMaskBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        mMaskCanvas = new Canvas(mMaskBitmap);

        if (mSetBoundsOnSizeAvailable)
        {
            mBackground.setBounds(0, 0, w, h);
            mSetBoundsOnSizeAvailable = false;
        }
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        // Draw background
        mBackground.draw(mBackgroundCanvas);

        // Draw mask
        mMaskCanvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR);
        super.onDraw(mMaskCanvas);

        mBackgroundCanvas.drawBitmap(mMaskBitmap, 0.f, 0.f, mPaint);
        canvas.drawBitmap(mBackgroundBitmap, 0.f, 0.f, null);
    }
}

在我的片段中:

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    vLoginBtn = (Button) view.findViewById(R.id.btn_login);
    vRegistrationBtn = (Button) view.findViewById(R.id.btn_registration);
    vForgotBtn = (Button) view.findViewById(R.id.btn_forgot);
    vBackground = (KenBurnsView) view.findViewById(R.id.login_background);
    vTitle = (SeeThroughTextView) view.findViewById(R.id.txt_view_login_title);
    vBackground.setResourceUrls(
            "http://www.youwall.com/papel/peaceful_place_wallpaper_4f3f3.jpg",
            "http://www.fwallpaper.net/wallpapers/P/E/Peaceful-Scenary_1920x1200.jpg",
            "http://p1.pichost.me/i/39/1620902.jpg"
    );
    vBackground.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
        @Override
        public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
            vTitle.setBackgroundDrawable(getResources().getDrawable(R.drawable.drawable_background_login_top));
            vTitle.invalidate();
            vBackground.removeOnLayoutChangeListener(this);
        }
    });

}

可绘制对象只有两种形状,一种是左上角和右上角的半径为 10dp,另一种是底部的半径。 具有顶部可绘制形状的自定义 TextView 位于包含 EditTextRelativeLayout 之上。 没有多少火箭科学。非常感谢 @Klotor 提出这个想法!