Android-Leinwand: Zeichnen Sie transparenten Kreis auf Bild

Ich schaffe ein Pixel-Jagd-Spiel. Also meine Aktivität zeigt ein ImageView. Und ich möchte einen Hinweis "Zeig mir wo ist das Objekt" zu schaffen. Dazu muss ich das ganze Bild außer einem Kreis um einen Punkt verschwimmen lassen, wo sich das Objekt befindet. Statt der Unschärfe kann ich nur einen halbtransparenten schwarzen Hintergrund zeigen. Es gibt kein Problem, ein halbtransparentes Rechteck auf der Leinwand zu zeichnen. Aber ich weiß nicht, wie man einen transparenten Kreis von ihm schneidet. Das Ergebnis soll so aussehen: Bildbeschreibung hier eingeben

Bitte helfen Sie mir, das gleiche Ergebnis auf Android SDK zu erzielen.

  • Android deaktivieren Listenansicht Elemente
  • Verschlüsselung mit AES-128 in Android und IPhone (unterschiedliches Ergebnis)
  • GSON: benutzerdefinierte Objektdeserialisierung
  • Wie man eine FM Radio Anwendung in Android zu machen
  • Mit Google OAuth 2 auf eingebettetem Android-basiertem Gerät
  • Wie man Debug-und Release-Version auf Android-Gerät zu verwalten?
  • Klicken Sie auf nicht vollständig sichtbar imageButton mit Espresso
  • RelativeLayout: align View zentriert horizontal oder vertikal relativ zu anderen Ansicht
  • Ist es möglich, benachrichtigt zu werden (zB E-Mail), wenn die Google Play Developer Console einen Crash oder ANR erhält?
  • Wie kann ich einen Android Switch schreiben?
  • Wie konvertiere ich JSONArray in die Liste mit Gson?
  • Gibt es einen Neun-Patch-Loader für iPhone?
  • 6 Solutions collect form web for “Android-Leinwand: Zeichnen Sie transparenten Kreis auf Bild”

    So endlich habe ich das geschafft.

    Zuerst zeichne ich ein halbtransparentes schwarzes Rechteck auf die ganze Ansicht. Danach mit PorterDuff.Mode.CLEAR schneide ich einen transparenten Kreis, um die Position der Katze zu zeigen.

    Ich hatte Probleme mit PorterDuff.Mode.CLEAR : Zuerst bekam ich einen schwarzen Kreis statt einer transparenten.

    Danke an Romain Guys Kommentare hier: Kommentar hier Ich habe verstanden, dass mein Fenster undurchsichtig ist und ich auf eine andere Bitmap ziehen sollte. Und erst nach dem Zug auf die Leinwand von View .

    Hier ist meine onDraw Methode:

     private Canvas temp; private Paint paint; private Paint p = new Paint(); private Paint transparentPaint; private void init(){ temp = new Canvas(bitmap); Bitmap bitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888); paint = new Paint(); paint.setColor(0xcc000000); transparentPaint = new Paint(); transparentPaint.setColor(getResources().getColor(android.R.color.transparent)); transparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); } protected void onDraw(Canvas canvas) { temp.drawRect(0, 0, temp.getWidth(), temp.getHeight(), paint); temp.drawCircle(catPosition.x + radius / 2, catPosition.y + radius / 2, radius, transparentPaint); canvas.drawBitmap(bitmap, 0, 0, p); } 

    Ich habe es auf diese Weise getan, indem ich benutzerdefinierte LinearLayout :

    Überprüfe den Screenshot :

    Bildbeschreibung hier eingeben

    CircleOverlayView.java

     import android.annotation.TargetApi; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.RectF; import android.os.Build; import android.util.AttributeSet; import android.widget.LinearLayout; /** * Created by hiren on 10/01/16. */ public class CircleOverlayView extends LinearLayout { private Bitmap bitmap; public CircleOverlayView(Context context) { super(context); } public CircleOverlayView(Context context, AttributeSet attrs) { super(context, attrs); } public CircleOverlayView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public CircleOverlayView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); if (bitmap == null) { createWindowFrame(); } canvas.drawBitmap(bitmap, 0, 0, null); } protected void createWindowFrame() { bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); Canvas osCanvas = new Canvas(bitmap); RectF outerRectangle = new RectF(0, 0, getWidth(), getHeight()); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(getResources().getColor(R.color.colorPrimary)); paint.setAlpha(99); osCanvas.drawRect(outerRectangle, paint); paint.setColor(Color.TRANSPARENT); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT)); float centerX = getWidth() / 2; float centerY = getHeight() / 2; float radius = getResources().getDimensionPixelSize(R.dimen.radius); osCanvas.drawCircle(centerX, centerY, radius, paint); } @Override public boolean isInEditMode() { return true; } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); bitmap = null; } } 

    CircleDrawActivity.java :

     public class CircleDrawActivity extends AppCompatActivity{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_circle_draw); } } 

    Activity_circle_draw.xml :

     <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/rlParent" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/lighthouse" android:scaleType="fitXY" /> <common.customview.CircleOverlayView android:id="@+id/cicleOverlay" android:layout_width="match_parent" android:layout_height="match_parent"> </common.customview.CircleOverlayView> </RelativeLayout> 

    Colors.xml :

     <?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorPrimary">#3F51B5</color> <color name="colorPrimaryDark">#303F9F</color> <color name="colorAccent">#FF4081</color> </resources> 

    Dimens.xml :

     <resources> <!-- Default screen margins, per the Android Design guidelines. --> <dimen name="nav_header_vertical_spacing">16dp</dimen> <dimen name="nav_header_height">160dp</dimen> <!-- Default screen margins, per the Android Design guidelines. --> <dimen name="activity_horizontal_margin">16dp</dimen> <dimen name="activity_vertical_margin">16dp</dimen> <dimen name="fab_margin">16dp</dimen> <dimen name="radius">50dp</dimen> </resources> 

    Hoffe das wird dir helfen

    Ich fand eine Lösung ohne Bitmap Zeichnung und Schöpfung. Hier ist das Ergebnis meiner Umsetzung: Beispiel für Overlay-Zeichnung

    Sie müssen eine benutzerdefinierte FrameLayout erstellen und drawCircle mit Clear paint:

      mBackgroundPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); 

    Vergessen Sie auch nicht, die Hardwarebeschleunigung zu deaktivieren und setWillNotDraw(false) da wir die onDraw Methode überschreiben

      setWillNotDraw(false); setLayerType(LAYER_TYPE_HARDWARE, null); 

    Das vollständige Beispiel ist hier:

     public class TutorialView extends FrameLayout { private static final float RADIUS = 200; private Paint mBackgroundPaint; private float mCx = -1; private float mCy = -1; private int mTutorialColor = Color.parseColor("#D20E0F02"); public TutorialView(Context context) { super(context); init(); } public TutorialView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public TutorialView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public TutorialView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(); } private void init() { setWillNotDraw(false); setLayerType(LAYER_TYPE_HARDWARE, null); mBackgroundPaint = new Paint(); mBackgroundPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); } @Override public boolean onTouchEvent(MotionEvent event) { mCx = event.getX(); mCy = event.getY(); invalidate(); return true; } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(mTutorialColor); if (mCx >= 0 && mCy >= 0) { canvas.drawCircle(mCx, mCy, RADIUS, mBackgroundPaint); } } } 

    PS: Diese Implementierung zieht nur Loch in sich selbst, du musst Hintergrund in dein Layout setzen und diesen TutorialView oben hinzufügen.

    @ Robert's Antwort hat mir tatsächlich gezeigt, wie man dieses Problem lösen kann, aber sein Code funktioniert nicht. Also habe ich seine Lösung aktualisiert und es funktionierte:

     public class CaptureLayerView extends View { private Bitmap bitmap; private Canvas cnvs; private Paint p = new Paint(); private Paint transparentPaint = new Paint();; private Paint semiTransparentPaint = new Paint();; private int parentWidth; private int parentHeight; private int radius = 100; public CaptureLayerView(Context context) { super(context); init(); } public CaptureLayerView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { transparentPaint.setColor(getResources().getColor(android.R.color.transparent)); transparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); semiTransparentPaint.setColor(getResources().getColor(R.color.colorAccent)); semiTransparentPaint.setAlpha(70); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); bitmap = Bitmap.createBitmap(parentWidth, parentHeight, Bitmap.Config.ARGB_8888); cnvs = new Canvas(bitmap); cnvs.drawRect(0, 0, cnvs.getWidth(), cnvs.getHeight(), semiTransparentPaint); cnvs.drawCircle(parentWidth / 2, parentHeight / 2, radius, transparentPaint); canvas.drawBitmap(bitmap, 0, 0, p); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { parentWidth = MeasureSpec.getSize(widthMeasureSpec); parentHeight = MeasureSpec.getSize(heightMeasureSpec); this.setMeasuredDimension(parentWidth, parentHeight); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } } 

    Und nun benutze diese Ansicht in jedem Layout wie folgt:

     <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <SurfaceView android:id="@+id/surfaceView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center"> </SurfaceView> <com.example.myapp.CaptureLayerView android:layout_width="match_parent" android:layout_height="match_parent" /> <Button android:id="@+id/btnTakePicture" android:layout_width="match_parent" android:layout_height="80dp" android:onClick="onClickPicture" android:text="@string/take_picture"> </Button> 

    Hier wünschte ich eine halbtransparente Schicht auf der SurfaceView mit transparentem Kreis in der Mitte. PS Dieser Code ist nicht optimiert, weil er Bitmap in der onDraw-Methode erstellt, weil ich die Größe und Höhe der übergeordneten Ansicht nicht in der init-Methode bekommen konnte, also konnte ich sie nur in onDraw kennen.

    Ich habe nicht viel zu deiner Antwort hinzufügen, aber wenn jemand interessiert ist, habe ich die Bitmap-Zuweisung verschoben und alle auf onSizeChanged, also ist es besser Leistung weise.

    Hier finden Sie ein FrameLayout mit einem "Loch" in der Mitte davon;)

     import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.os.Handler; import android.util.AttributeSet; import android.util.Log; import android.widget.FrameLayout; /** * Created by blackvvine on 1/1/16. */ public class SteroidFrameLayout extends FrameLayout { private Paint transPaint; private Paint defaultPaint; private Bitmap bitmap; private Canvas temp; public SteroidFrameLayout(Context context) { super(context); __init__(); } public SteroidFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); __init__(); } public SteroidFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); __init__(); } private void __init__() { transPaint = new Paint(); defaultPaint = new Paint(); transPaint.setColor(Color.TRANSPARENT); transPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); setWillNotDraw(false); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); temp = new Canvas(bitmap); } @Override protected void dispatchDraw(Canvas canvas) { temp.drawColor(Color.TRANSPARENT); super.dispatchDraw(temp); temp.drawCircle(cx, cy, getWidth()/4, transPaint); canvas.drawBitmap(bitmap, 0, 0, defaultPaint); if (p < 1) invalidate(); else animRunning = false; } } 

    Ps: obwohl es viel effizienter als die ursprüngliche Antwort ist es immer noch eine relativ schwere Aufgabe, in einer draw () -Methode zu tun, also wenn Sie diese Technik in einer Animation wie mich verwenden, erwarten Sie nicht eine 60.0fps glatt

    Das hat für mich gearbeitet

     canvas.drawCircle(x,y,radius,new Paint(Color.TRANSPARENT)) 
    Das Android ist ein Google Android Fan-Website, Alles ├╝ber Android Phones, Android Wear, Android Dev und Android Spiele Apps und so weiter.