# Button in SurfaceView integrieren



## AkechiKogoro (23. Jul 2020)

Hallo an alle im Java-Forum,

ich habe folgendes Problem: 
Ich habe eine Klasse "GameView" geschrieben, die die Klasse SurfaceView erweitert. Bei der Erzeugung eines GameView-Objektes mit "private GameView gameView = new GameView(this);" wird ja mit "this" der gesamte Context der App und damit die ganze Oberfläche in die GameView einbezogen ( so viel ich weiß ).
Im Konstruktor dieser Klasse wird mit "SurfaceHolder myHolder = getHolder();" auf Basis der GameView ( erweiterte SurfaceView) ein SurfaceHolder erzeugt, mit dem ich die Spielfigur laufen lassen kann. So weit funktioniert das auch. Jedoch läuft die Figur nur los wenn man irgendwo auf den Bildschirm tippt.
Jetzt möchte ich aber ein ein Button ( als Anfang für ein Steuerkreuz ) einbeziehen und will damit erreichen dass die Spielfigur nur losläuft, wenn man diesen Button betätigt. 
Was noch zu erwähnen ist: In der onCreate()-Methode steht bei mir "setContentView(gameView)"

Wie kann ich über die SurfaceView einen Button legen? Oder gibt es eine andere Möglichkeit dies zu realisieren?

Ich hoffe dass mir diesbezüglich jemand weiterhelfen kann.

Viele Grüße
euer Akechi Kogoro


----------



## mihe7 (23. Jul 2020)

Aus der Doku 


			
				https://developer.android.com/reference/android/view/SurfaceView hat gesagt.:
			
		

> The surface is Z ordered so that it is behind the window holding its SurfaceView; the SurfaceView punches a hole in its window to allow its surface to be displayed. The view hierarchy will take care of correctly compositing with the Surface any siblings of the SurfaceView that would normally appear on top of it. This can be used to place overlays such as buttons on top of the Surface, though note however that it can have an impact on performance since a full alpha-blended composite will be performed each time the Surface changes.


Sprich: ein Layout erstellen, das neben der SurfaceView ein weiteres Layout mit den Buttons enthält. Beispiel hierzu unter https://stackoverflow.com/a/5779267


----------



## AkechiKogoro (24. Jul 2020)

Ich habe es nach dem Schema versucht wie du es vorgeschlagen hast @mihe7, jedoch leider ohne Erfolg. Hier ein Auszug aus dem was ich gemacht habe:

_<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ImageButton
        android:id="@+id/iBtnNachRechts"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:srcCompat="@android:drawable/ic_media_play" />

    <com.example.runningman2.MainActivity.GameView
        android:id="@+id/gameView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginBottom="8dp"
        app:layout_constraintBottom_toTopOf="@+id/iBtnNachRechts"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>_

Und im Activity selbst:

...
_@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);  -> Zeile 24
    gameView = findViewById(R.id.gameView);
}_
...

_Daraufhin ist folgender Fehler aufgetreten:_

E/AndroidRuntime: FATAL EXCEPTION: main
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.runningman2/com.example.runningman2.MainActivity}: android.view.InflateException: Binary XML file line #20: Error inflating class com.example.runningman2.MainActivity.GameView
...
at com.example.runningman2.MainActivity.onCreate(MainActivity.java:24)

( Ich habe keine Ahnung warum er die "activity_main", in der sich jetzt die GameView "gameView" befundet nicht mehr findet )


----------



## mihe7 (24. Jul 2020)

AkechiKogoro hat gesagt.:


> Ich habe keine Ahnung warum er die "activity_main", in der sich jetzt die GameView "gameView" befundet nicht mehr findet


Ist das eine innere Klasse? Gem. https://developer.android.com/guide/topics/ui/custom-components funktioniert diese Art der Deklaration nur mit Klassen, die nicht in anderen Klassen eingebetettet wurden.


----------



## AkechiKogoro (24. Jul 2020)

"activity_main" ist das Layout und "gameView" ist ein GameView-Objekt ( eine Ableitung aus der Klasse SurfaceView ). Ich habe versucht die GameView "gameView" innerhalb ( mit XML ) des Layouts "activity_main" und dort im _ConstraintLayout_ zu integrieren. Das hat leider aber nicht funktioniert.

Mir ist in der DesignAnsicht noch folgende Warnmeldung aufgefallen:
_The following classes could not be found:
- com.example.runningman2.MainActivity.GameView (Fix Build Path, Edit XML, Create Class)_

( In der XML-Ansicht wird nichts beanstandet, weswegen ich die Warnmeldung erst später entdeckt hatte )
Wenn es daran liegen sollte: Wie kann ich das korrigieren? ( Die Klasse existiert ja immerhin in der Activity ).


----------



## mihe7 (24. Jul 2020)

Das hier _com.example.runningman2.MainActivity.GameView_ sieht aus, als hättest Du die *Klasse* GameView innerhalb der Klasse MainActivity definiert. Das funktioniert so nicht. Du musst die Klasse GameView in einer eigenen Datei definieren und den vollqualifizierten Namen der Klasse angeben. Alternative dazu findest Du in dem Link oben.


----------



## AkechiKogoro (24. Jul 2020)

Danke für den Tipp. Die Klasse wird jetzt erkannt.
Jedoch hat die App schon wieder 2 neue Probleme aus denen ich nicht schlau werde:
_*Render Problem*
Custom view GameView is not using the 2- or 3-argument View constructors; XML attributes will not work   
Tip: Try to refresh the layout.

*Render Problem*
Color spaces are not supported   
Tip: Try to refresh the layout_

Der refresh hat aber leider nichts geändert.


----------



## mihe7 (24. Jul 2020)

Das steht alles in dem Link, z. B. "There is a form of the constructor that are called when the view is created from code and a form that is called when the view is inflated from a layout file. The second form should parse and apply any attributes defined in the layout file."

Gib Deiner Klasse alle Konstruktoren, die auch SurfaceView hat und rufe super(...) auf.


----------



## AkechiKogoro (24. Jul 2020)

Mein bisher schon verwendeter Konstruktor sieht folgendermaßen aus:
_public GameView(Context context ) {
    super(context);
    ourHolder = getHolder();
    bitmapRunningMan = BitmapFactory.decodeResource(getResources(), R.drawable.running_man);
    bitmapRunningMan = Bitmap.createScaledBitmap(bitmapRunningMan, frameWidth * frameCount, frameHight, false);
}_

Die anderen Konstrunktoren benötigen ebenfalls alle einen Context:

SurfaceView(Context context)SurfaceView(Context context, AttributeSet attrs)SurfaceView(Context context, AttributeSet attrs, int defStyleAttr)SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)

Wie kann ich nun ( ggf. damit ) realisieren dass sich die GameView nicht die ganze Oberfläche schnappt, damit ich darunter noch den Button packen kann?

Auch meckert der Compiler noch an folgender Zeile rum:
_setContentView(R.layout.activity_main);_
Das macht er aber erst seit ich die GameView wie folgt in die XML-Datei "activity_main" geschrieben hab_e _( Deswegen denke ich ist der Konstruktor nicht das Problem, denn der wird erst in der Zeile danach aufgerufen ).

_<com.example.runningman2.GameView
    android:id="@+id/gameView"
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:layout_marginBottom="8dp"
    app:layout_constraintBottom_toTopOf="@+id/iBtnNachRechts"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />_

Die gleichen Warnungen aus in meinem Beitrag von heute 15:58 Uhr sind leider noch immer darin sichtbar.


----------



## mihe7 (25. Jul 2020)

AkechiKogoro hat gesagt.:


> Die gleichen Warnungen aus in meinem Beitrag von heute 15:58 Uhr sind leider noch immer darin sichtbar.



Natürlich. In der Warnung steht doch ganz klar das Problem:


AkechiKogoro hat gesagt.:


> Custom view GameView is not using the 2- or 3-argument View constructors



Du brauchst also Konstruktoren wie


```
public GameView(Context context, AttributeSet attrs) {
    super(context, attrs);
    // ...
}
```


----------



## AkechiKogoro (25. Jul 2020)

Danke @mihe7,
dank deiner Hilfe hat es jetzt endlich geklappt. Ich hätte nicht gedacht dass es daran liegt dass ich nicht alle Konstruktoren aus SurfaceView umgesetzt hatte. Da habe ich wieder etwas gelernt.

Vielen Dank nochmal!


----------

