Popup-Menü auf Canvas Oberfläche

  • Antworten:27
  • OffenNicht stickyBentwortet
  • Forum-Beiträge: 40

06.12.2018, 17:46:00 via Website

Hallo!
Wie kann ich ein Popup-Menü auf meiner Canvas-Oberfläche erscheinen lassen. Ich möchte, wenn ich auf eine bestimmte stelle in meiner Canvas-Oberfläche drücke, dass es mir an dieser stelle ein Popup-Menü zeigt.
Das drücken kann ich damit auswerten:

public boolean onTouchEvent(MotionEvent event) {

        int xClick = (int)event.getX();
        int yClick = (int)event.getY();

        xClick = (xClick - xM) / m;
        yClick = yClick / m;

        if (80 <= xClick && xClick <= 90    &&    70 <= yClick && yClick <= 80){
            //MenuAnzeigen
        }

        return true;
    }

Danke im Voraus!:D

Diskutiere mit!
Beste Antwort
  • Forum-Beiträge: 777

24.01.2019, 19:54:38 via Website

Meinen Ratschlag eine unsichtbarer View zu erstellen und an diese das PupupMenu anzuheften hast du scheinbar nicht verfolgt. Hatte dir auch ein paar Links dazu gegeben. Das was die jetzt hast ist eigentlich wieder der Anfang den du schon hattest. Ich habe ja gesagt das du wenn es auf so alten Android Versionen laufen soll einen anderen Aufbau brauchst.

So ich habe mal ein einfaches Projekt erstellt. Was dir dein Touch Event aus der View Klasse mittels eines Listner an die Activity weiter gibt. Dort estelle ich eine unsichtbare View und an dieser hefte ich das Popup an. Danach wird die View wieder entfernt. Dazu bauchst du aber ein Layout als Container in dem deine View Läuft. Habe dafür ein einfaches Linearlayout genommen.
Es sollte auch unter API 17 laufen.

https://drive.google.com/open?id=1xX5uco2z0BlkMuTEcdi2lZdoVg1oamgo

Hilfreich?
Diskutiere mit!
Ludy
  • Mod
  • Blogger
  • Forum-Beiträge: 7.443

06.12.2018, 21:52:47 via Website

Hallo,

deine Zeile if (80 <= xClick && xClick <= 90 && 70 <= yClick && yClick <= 80){ hat redundant Anteile!

So sollte es reichen ;-) if ( (xClick <= 90) && (yClick <= 80) ) {

Beim #onTouchEvent wird mit den einzelnen Events gearbeitet um eine mehrfach Ausführung unterbunden wird.

@Override
public boolean onTouchEvent(MotionEvent event) {

    switch(event.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            int xClick = Math.round(event.getX());
            int yClick = Math.round(event.getY());

            xClick = (xClick - xM) / m;
            yClick = yClick / m;

            if ( (xClick <= 90) && (yClick <= 80) ) {
                PopupMenu popupMenu = new PopupMenu(mContext, viewVonIrgendwas) {
                    @Override
                    public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
                        switch (item.getItemId()) {
                            case R.id.irgendwas:
                                // ToDo was passiert
                                return true;
                            default:
                                return super.onMenuItemSelected(menu, item);
                        }
                    }
                };
                popupMenu.inflate(R.menu.overflow_menu);
                popupMenu.show();
            }
        return true;
        }
    }
}

Alle Angaben sind ohne Gewähr.

Gruß Ludy (App Entwickler)

Mein Beitrag hat dir geholfen? Lass doch ein "Danke" da.☺

Download Samsung Firmware Tool

Meine Wunschliste

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 40

11.12.2018, 18:19:22 via Website

Hallo.
Danke für deine Antwort! Bisher habe ich damit aber keinen Erfolg. Bei

@Override
public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item)

kommt

Method does not override method from its superclass

Was muss ich verändern, damit dass funktioniert?

Die Zeile if (80 <= xClick && xClick <= 90 && 70 <= yClick && yClick <= 80)
kann nicht vereinfacht werden!
Wenn man es so schreibt, könnte es vereinfacht werden if (80 >= xClick && xClick <= 90 && 70 >= yClick && yClick <= 80)

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 3.241

12.12.2018, 08:44:02 via Website

Hallo ,

zu A) - Du musst deine Hauptklasse entsprechend vererben.
zu B) - Dein If Statement macht trotzdem keinen Sinn, da hat Ludy durchaus recht.

Anmerkung zu A : Wenn du noch Anfänger in Sachen OOP Entwicklung bist, kann ich nur wärmstens das Erlernen der Grundlagen empfehlen.

— geändert am 12.12.2018, 09:05:53

Liebe Grüße - Stefan
[ App - Entwicklung ]

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 777

12.12.2018, 10:18:10 via Website

Hallo erstens müsste die Methode so heißen.

@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
    return super.onMenuItemSelected(featureId, item);
}

Dies geht aber nur in einer von Activity geerbten Klasse
https://developer.android.com/reference/android/app/Activity.html#onMenuItemSelected(int,%20android.view.MenuItem)

In einer von AppCompacktActivity geerbten Klasse geht es nicht da dort die Methode final ist.
https://developer.android.com/reference/android/support/v7/app/AppCompatActivity.html#onKeyDown(int,%20android.view.KeyEvent)

Benutze da die Methode

   boolean onMenuOpened (int featureId,        Menu menu)

@saw00

zu A) - Du musst deine Hauptklasse entsprechend vererben.

In welcher Klasse ist den die Methode ?
onMenuItemSelected(MenuBuilder menu, MenuItem item)

— geändert am 12.12.2018, 11:13:51

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 3.241

12.12.2018, 10:29:02 via Website

@Jokel

da ich bei ihm nicht einsehen konnte, worin er das ganze versucht umzusetzen (z.b Activity), hatte ich diese Antwort eher global gesehen.
(Es hätte ja irgend eine selbst angelegte pseudo klasse sein)

Und auf seine Parameter hatte ich dann gar nicht mehr geachtet.
Das hast du ja treffend getan :-)

— geändert am 12.12.2018, 10:33:45

Liebe Grüße - Stefan
[ App - Entwicklung ]

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 777

12.12.2018, 10:48:52 via Website

Bei dem If bin ich leider auch der Meinung das es richtig ist

if ((80 <= xClick && xClick <= 90)&& (70 <= yClick && yClick <= 80))

Er will einen Klick wenn X zwischen 80 und 90 liegt und Y zwischen 70 und 80 haben
sonnst nicht.

Wenn xClick zum zB. 85 ist, ist 80 <= xClick true, und xClick <= 90 auch true, Ergebnis true.
ist xClick= 70, ist ist 80 <= xClick false, und xClick <= 90 true , Ergebnis false.
ist xClick= 99, ist ist 80 <= xClick true , und xClick <= 90 false, Ergebnis false.

PS.

Und auf seine Parameter hatte ich dann gar nicht mehr geachtet.

waren auch die Parameter von Ludy.

— geändert am 12.12.2018, 11:11:09

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 3.241

12.12.2018, 11:32:43 via Website

Und schon wieder so ein Fall von Übersichtlichkeit :-)

if ( ((x >= 80) && (x <= 90)) && ((y >= 70) && (y <= 80)) )
{
// true
}

@Jokel - Rein aus Interesse :
Schreibst du das auch so , wie der TE , weil du direkt drauf kamst ?
Ludy hat zumindest auf Anhieb gleich "falsch" gelesen , wie ich.

— geändert am 12.12.2018, 11:41:13

Liebe Grüße - Stefan
[ App - Entwicklung ]

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 777

12.12.2018, 15:36:14 via Website

Schreibst du das auch so , wie der TE , weil du direkt drauf kamst ?

Was meist du damit? Ich habe den Code nicht abgetippt und in AS eingefügt wenn du das meinst.
Mit den Klammern ist es natürlich übersichtlicher auch eindeutiger sollte aber auch ohne den Klammern gehen. Da es alles „Und“ Verknüpfungen sind.

(x >= 80) && (x <= 90) ist das gleiche wie (80 <= x) && (x<=90)

(x >= 80) = (80 <= x)

https://de.wikipedia.org/wiki/Vergleich_%28Zahlen%29

PS. Ok die Schreibweise ist aus Programmierer sicht etwas unüblich.
Mathematisch ist es das gleiche.
a < X < b

— geändert am 12.12.2018, 16:39:52

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 777

12.12.2018, 17:43:57 via Website

das Popup würde ich so machen

PopupMenu popupMenu = new PopupMenu(mContext, viewVonIrgendwas); 
popupMenu.setOnMenuItemClickListener( new PopupMenu.OnMenuItemClickListener(){
        @Override
        public boolean onMenuItemClick(MenuItem item) {
                    switch (item.getItemId()) {
                        case R.id.irgendwas:
                            // ToDo was passiert
                            return true;
                        default:
                            return super.onMenuItemClick(item);

                    }   
        }       
});
popupMenu.inflate(R.menu.overflow_menu);
popupMenu.show();

overflow_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/irgendwas"
        android:icon="@drawable/ic_irgendwas"
        android:title="irgendwas" />
</menu>

— geändert am 12.12.2018, 17:45:54

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 40

18.12.2018, 17:31:45 via Website

Hallo!
Das If hat mich anfangs auch verwirrt, aber Android Studio hat mich korrigiert.

Die Methode onTouchEvent() befindet sich in der von mir erstellten MyCanvas.java.

public class MyCanvas extends View {

}

onMenuItemClick() Funktioniert in dieser Klasse nicht.
Eine View, wozu dann das menu gehört, habe ich auch nicht. Nur ein ConstraintLayout, in dem MyCanvas.java eingebunden wird.

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 777

18.12.2018, 19:54:17 via Website

Hallo
Du erstellst hiermit ein Popup Menu
PopupMenu popupMenu = new PopupMenu(mContext, viewVonIrgendwas);

mContext = Context der Activity
viewVonIrgendwas = deine View im Layout, gib ihr eine ID und suche sie mit findViewbyID

Hiermit setzt du auf das eben erstelle Menu einen KlickListener
popupMenu.setOnMenuItemClickListener( new PopupMenu.OnMenuItemClickListener(){
@Override
public boolean onMenuItemClick(MenuItem item) {

Und da sollte es die Methode onMenuItemClick() schon geben.

Mit diesen zwei Zeilen Inflatest du das Menu aus der XML Datei und zeigst es an.

popupMenu.inflate(R.menu.overflow_menu);
popupMenu.show();

Kannst du denn ein PopupMenu in deiner View Klasse erstellen? Wenn das nicht geht, geht der Rest auch nicht.
Oder du brauchst den Context der Activity zum erstellen des PopupMenu.

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 40

19.12.2018, 16:19:45 via Website

Hallo @Jokel!
Danke für die Erklärung.

Von meiner MyCanvas.java kann ich jetzt hiermit:

@Override
    public boolean onTouchEvent(MotionEvent event) {

        switch(event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                int xClick = Math.round(event.getX());
                int yClick = Math.round(event.getY());

                xClick = (xClick - xM) / m;
                yClick = yClick / m;

                if ( 80 <= xClick && xClick <= 90    &&    70 <= yClick && yClick <= 80)  {
                    PopupMenu popupMenu = new PopupMenu(getContext(), findViewById(R.id.myCanvas));
                    popupMenu.inflate(R.menu.menu_w1);
                    popupMenu.show();
                }
                return true;
            }
        }
        return true;
    }

Ein Menu erstellen. Leider erscheint es wie erwartet nicht an der stelle, wo es hin soll. Es soll dort erscheinen, wo ich geklickt habe. Neben dem wird es auch nur ganz klein angezeigt. Wie kann man das verändern? Anbei ein Bild:
image

— geändert am 19.12.2018, 16:20:39

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 3.241

19.12.2018, 16:52:00 via Website

Hallo,

bis jetzt habe ich mich herausgehalten ....

Ein Canvas aktualisiert in regelmäßigen Abständen selbständig.
Kein wunder , dass dein Canvas immer in den Vordergrund kommt.

Ich würde mir einen separaten RelativeLayout Container bauen , in dem der Canvas-View implementiert ist.
In dem Moment , indem du ein View Overlay willst, solltest du ein Flag setzen , dein OnDraw disabeln, dein View ( oder Menu) anzeigen und bei Verlassen dein OnDraw mit dem Flag fortsetzen.

Desweiteren würde ich das genestete CanvasView im Container auch disabeln.

PopupMenu postionieren : setX,setY oder so
https://developer.android.com/reference/android/widget/PopupWindow#showAsDropDown(android.view.View,%20int,%20int)

— geändert am 19.12.2018, 17:04:16

Liebe Grüße - Stefan
[ App - Entwicklung ]

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 777

19.12.2018, 17:23:45 via Website

Hallo @saw00

Ein Canvas aktualisiert in regelmäßigen Abständen selbständig.

Nach meinem Verständnis ist das doch nur bei einem SurfaceView so.
Berichtige mich wenn ich Falsch liege.

Mir scheit das er nur ein einfaches View hat. Das mit dem Aktualisieren sollte somit kein Thema sein den das muss er selber anstoßen.

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 40

19.12.2018, 18:39:04 via Website

@Jokel
Wenn ich postInvalidateDelayed(); entferne, wird das PopupMenu trotzdem noch so klein angezeigt.

@swa00
Wie funktioniert das mit so einem Flag?

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 777

19.12.2018, 19:18:22 via Website

@PBahner mit "postInvalidateDelayed()" hat die Grösse auch nichts zu tuhen, nur mit dem Aktualisieren der Grafik.
Wenn du ein ständiges neue zeichnen deiner View hättest so wie zB einer surfaceView würdest du das neu zeichnen anhalten.

Das flag würdest du setzen wenn dein Menu sichtbar ist und und wenn dein Menu fertig ist löschst du es wieder . Damit, ich sage mal automatiche neuzeichnung. ausgesetz wird.

Ich denke du hast kein selbstständiges neuzeichnen , das macht du doch glaube ich selber mit postInvalidate() wenn du etwas verändert hast, also Event gesteuert und nicht automatisch oder?

Zum verändern des Style schau mal hier.
https://stackoverflow.com/questions/47963835/changing-the-popup-menu-size

— geändert am 19.12.2018, 21:08:51

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 40

04.01.2019, 15:08:37 via Website

Ich habe das hier probiert:

  <style name="MyPopupMenu" parent="@style/Widget.AppCompat.PopupMenu">
            <item name="android:dropDownHorizontalOffset">100dp</item>
            <item name="android:dropDownVerticalOffset">100dp</item>
            parent="@style/Widget.AppCompat.PopupMenu.Overflow"
            <item name="popupMenuStyle">@style/MyPopupMenu</item>
        </style>

Es hat leider zu keinem Ergebnis geführt. Ich kann die position nur mit Gravity.... verändern. Und die größe habe ich auch nicht verändern können.

Es kommt noch dazu, dass ich einige codes aus dem Internet probiert habe um das klicken auf das Menü auszuwerten und nichts davon funktioniert hat(angry)

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 777

04.01.2019, 21:19:32 via Website

Hallo Zeige mal bitte deine gesamte style. Xml Datei. Achte bitte auch darauf das nicht die spitzen klammern abgeschnitten werden.

Auf jedenfall musst du den neuen style auch in deinem apptheme mit ein binden ob du das hast kann ich nicht sehen.

<style name="AppTheme" parent="Theme.AppCompat.Light">
     <item name="popupMenuStyle">@style/MypopupMenu</item>
</style>

<style name="MypopupMenu" parent="Widget.AppCompat.PopupMenu">
     <item name="android:popupBackground">@android:color/white</item>
</style>

Hir noch ein link zu dem Thema hoffe das es dadurch etwas klarer wird was ich meine.

https://code.i-harness.com/en/q/143f72c

Ps.
Hast du den mal versucht die Schriffarbe zu ändern oder die Schriftgrösse?
Hat das geklappt?

Deine genannten style Optionen gehen nur wenn du das gravity auch auf end gesetzt hast. Bei default oben links kann das nicht gehen.
Denn der offset bestimmt die Ecke oben links vom PopupMenu. Und die ist bei default schon oben links im Layout.

Um die Position zu ändern hat dir saw00 schon einen Tipp gegeben.
Oder du veränderst das margin in den params die du dem popupmenue übergibst.

— geändert am 05.01.2019, 14:08:24

Hilfreich?
Diskutiere mit!
  • Forum-Beiträge: 40

07.01.2019, 17:46:35 via Website

Danke @Jokel! Ich habe nun Gravity.END eingefügt und den style in den appTheme eingebunden, womit es hat auf meinem Handy funktioniert. Auf meinem Tablet dagegen wird das menu gar nicht erst angezeigt. Nur, wenn ich

<item name="android:dropDownHorizontalOffset">-40dp</item>
<item name="android:dropDownVerticalOffset">200dp</item>

enferne, wird es oben links angezeigt.

Mein Handy hat API 27 und das Tablet API 17. Hat es vielleicht damit etwas damit zu tun?

hier noch mein styles.xml:

<resources>

    <style name="AppTheme" parent="Theme.AppCompat.Light">
        <item name="popupMenuStyle">@style/MyPopupMenu</item>
    </style>

    <style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>

    <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />

    <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />

    <style name="MyPopupMenu" parent="@style/Widget.AppCompat.PopupMenu">
        <item name="android:dropDownHorizontalOffset">-40dp</item>
        <item name="android:dropDownVerticalOffset">200dp</item>
        parent="@style/Widget.AppCompat.PopupMenu.Overflow"
    </style>
</resources>
Hilfreich?
Diskutiere mit!