How to create a transparent circle inside a rectangle shape in XML on Android?

I am trying to create the following project in my application.

Layout design
(https://photos.google.com/share/AF1QipPhCGTgf9zi7MetWJYm0NQ14c3wqzjqnEwxsajCFHEjqzt5R29qYvIjZ2C71q7EnQ?key=WUZKSXA1WVVwSlId1ujdjdjwjlj2ujrjdjdjujrjdjdjujdjdjdjwjlj2ujr

Its overlay on top of the main interface. Trying to create this using a layout on top of the main user interface with its background in the form of a translucent form created in XML. However, even after reading a few posts, I cannot figure it out.

I tried the following approach, but it did not work. I created a ring shape with a stroke of 200dp and set it as the source for the image, and then set the zoom type to centerCrop, but the shape does not scale like a bitmap does.

XML Form:

<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:innerRadius="0dp" android:shape="ring" android:thicknessRatio="2" android:useLevel="false" > <solid android:color="@android:color/transparent" /> <stroke android:width="200dp" android:color="#80000000" /> </shape> 

Layout Overlay:

 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:src="@drawable/onboarding_background" android:scaleType="centerCrop"/> </RelativeLayout> 

Any pointers to how to do this or code would be really helpful.

+7
android porter-duff
source share
3 answers

I recently played with something similar and adapted it for you. All magic happens in onDraw:

 public class FocusView extends View { private Paint mTransparentPaint; private Paint mSemiBlackPaint; private Path mPath = new Path(); public FocusView(Context context) { super(context); initPaints(); } public FocusView(Context context, AttributeSet attrs) { super(context, attrs); initPaints(); } public FocusView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initPaints(); } private void initPaints() { mTransparentPaint = new Paint(); mTransparentPaint.setColor(Color.TRANSPARENT); mTransparentPaint.setStrokeWidth(10); mSemiBlackPaint = new Paint(); mSemiBlackPaint.setColor(Color.TRANSPARENT); mSemiBlackPaint.setStrokeWidth(10); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPath.reset(); mPath.addCircle(canvas.getWidth() / 2, canvas.getHeight() / 2, 550, Path.Direction.CW); mPath.setFillType(Path.FillType.INVERSE_EVEN_ODD); canvas.drawCircle(canvas.getWidth() / 2, canvas.getHeight() / 2, 550, mTransparentPaint); canvas.drawPath(mPath, mSemiBlackPaint); canvas.clipPath(mPath); canvas.drawColor(Color.parseColor("#A6000000")); } } 

The trick here is to create a Path (transparent circle) so that we can set the method of drawing the path "out of the path" instead of "inside the path". Finally, we can just put the canvas on this path and fill in the black color.

For you, you just need to change Color.BLACK to your color, as well as change the desired radius.

EDIT: Oh and just add it programmatically: FocusView view = new FocusView(context) your_layout.addView(view)

Or via XML:

 <package_path_to_.FocusView android:layout_width="match_parent" android:layout_height="match_parent" /> 

EDIT2: I just saw that you wanted this to host your application. You might consider looking at https://github.com/iammert/MaterialIntroView , then

+10
source share

You can use PorterDuffXferMode and a custom view for this.

A good example of the different modes shown in this figure (see A Out B): AlphaCompositing

The idea is to create a custom view with an opaque black rectangle and surround it. When you apply PorterDuffXferMode.SRC_OUT, it β€œerases” the circle from the rectangle, so you get the result you want.

In your custom view, you must override the dispatchDraw (Canvas canvas) method and draw the result of the bitmap on your frame.

Then you can put the MapView and your custom view in FrameLayout and get the result.

+1
source share

I encountered such a problem that the code does not work on api lvl 16 from NSimon. I fixed the code and now it supports api 16+.

 public class FocusView extends View { private Paint mPaint; private Paint mStrokePaint; private Path mPath = new Path(); public FocusView(Context context) { super(context); initPaints(); } public FocusView(Context context, AttributeSet attrs) { super(context, attrs); initPaints(); } public FocusView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initPaints(); } private void initPaints() { mPaint = new Paint(); mPaint.setColor(Color.parseColor("#A6000000")); mStrokePaint = new Paint(); mStrokePaint.setColor(Color.YELLOW); mStrokePaint.setStrokeWidth(2); mStrokePaint.setStyle(Paint.Style.STROKE); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPath.reset(); float radius = 0; float strokeWidth = 0; if (canvas.getWidth() < canvas.getHeight()) { radius = canvas.getWidth() / 2 - 10; strokeWidth = (canvas.getHeight() - canvas.getWidth())/2; } else { radius = canvas.getHeight() / 2 - 10; strokeWidth = (canvas.getWidth() - canvas.getHeight())/2; } mPaint.setStrokeWidth(strokeWidth); mPath.addCircle(canvas.getWidth() / 2, canvas.getHeight() / 2, radius, Path.Direction.CW); mPath.setFillType(Path.FillType.INVERSE_EVEN_ODD); canvas.drawCircle(canvas.getWidth() / 2, canvas.getHeight() / 2, radius, mStrokePaint); canvas.drawPath(mPath, mPaint); } } 
0
source share

All Articles