CutoutTextView.java
Launch Plaid app and Go to Menu -> About
You will be able to see the text "PLAID" but look close you can actually see through it.
We can see that
there is textview PLAID and we can actually see through it . After seeing that
Portar Duff should be in your mind.
There is already a comment in the source code.
"A view which punches
out some text from an opaque color block, allowing you to see through it."
Really important
post before you do read further.
Lets see how this view is used in layout
1 2 3 4 5 6 | <io.plaidapp.ui.widget.CutoutTextView android:layout_width="match_parent" android:layout_height="@dimen/about_header_height" android:text="@string/app_name" app:foregroundColor="?android:colorPrimary" app:font="roboto-mono-regular" /> |
Custom stylable
attributes can be found in file attrs_cutout_text_view.xml
1 2 3 4 5 6 7 | <resources> <declare-styleable name="CutoutTextView"> <attr name="foregroundColor" format="color" /> <attr name="android:text" /> <attr name="font" /> </declare-styleable> </resources> |
Constructor is
really self explanatory , where we just get the staylable attributes from the
xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public CutoutTextView(Context context, AttributeSet attrs) { super(context, attrs); textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); final TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable .CutoutTextView, 0, 0); if (a.hasValue(R.styleable.CutoutTextView_font)) { textPaint.setTypeface(FontUtil.get(context, a.getString(R.styleable .CutoutTextView_font))); } if (a.hasValue(R.styleable.CutoutTextView_foregroundColor)) { foregroundColor = a.getColor(R.styleable.CutoutTextView_foregroundColor, foregroundColor); } if (a.hasValue(R.styleable.CutoutTextView_android_text)) { text = a.getString(R.styleable.CutoutTextView_android_text); } maxTextSize = context.getResources().getDimensionPixelSize(R.dimen.display_4_text_size); a.recycle(); } |
The
main call to onSizeChanged() is done after the construction of your view but
before the drawing. At this time the system will calculate the size of your
view and notify you by calling onSizeChanged()
CalculateTextPosition
: finds out the x,y co-ordinates within view so that the text is centered.
createBitmap :
creates a canvas -> draws over it using the textPaint.
But while doing that
it just punches a hole on the canvas using the Portar Duff
// this is the magic
– Clear mode punches out the bitmap
textPaint.setXfermode(new
PorterDuffXfermode(PorterDuff.Mode.CLEAR));
cutoutCanvas.drawText(text, textX,
textY, textPaint);
The overall effect
is we are able to see through the text and we are able to see some content of
the main recyclerview item that it in that position.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); calculateTextPosition(); createBitmap(); } private void calculateTextPosition() { float targetWidth = getWidth() / PHI; textSize = ViewUtils.getSingleLineTextSize(text, textPaint, targetWidth, 0f, maxTextSize, 0.5f, getResources().getDisplayMetrics()); textPaint.setTextSize(textSize); // measuring text is fun :] see: https://chris.banes.me/2014/03/27/measuring-text/ textX = (getWidth() - textPaint.measureText(text)) / 2; Rect textBounds = new Rect(); textPaint.getTextBounds(text, 0, text.length(), textBounds); float textHeight = textBounds.height(); textY = (getHeight() + textHeight) / 2; } private void createBitmap() { if (cutout != null && !cutout.isRecycled()) { cutout.recycle(); } cutout = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); cutout.setHasAlpha(true); Canvas cutoutCanvas = new Canvas(cutout); cutoutCanvas.drawColor(foregroundColor); // this is the magic – Clear mode punches out the bitmap textPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); cutoutCanvas.drawText(text, textX, textY, textPaint); } |
No comments:
Post a Comment