Button-Darstellung global modifizieren (nur bestimmte Parameter!)

  • Antworten:17
Arne
  • Forum-Beiträge: 41

20.06.2017, 11:22:34 via Website

Hallo,

ich bin hier ziemlich neu und muss offenbaren, dass ich mich in Sachen UI im Gegensatz zu Java und den Programmcodes selbst noch nicht wirklich auskenne.

Ein großes Fragezeichen erstreckt sich dabei über die Themen Styles (insbesondere was die Vererbung angeht) - XML-Dateien - Themes. Wenn also jemand Seiten oder Tutorials kennt, die diese Thematik SEHR leicht und verständlich erklären, wäre ich sehr dankbar!

Aktuell stehe ich vor dem folgenden, konkreten Problem:

Ich möchte, dass alle Buttons in meiner App, egal in welchem Zustand, runde Ecken bekommen (das geht irgendwie unter Android Background ... shape ... Corners ... radius). Der Rest soll quasi Default bleiben.
Ich habe herausgefunden, wie ich die Default-Werte für alle Buttons ändern kann, allerdings nicht, wie ich nur eine Eigenschaft (die mit den runden Ecken) ändere. D.h., ich muss gleich alle anderen Eigenschaften mitdefinieren, ansonsten wird der Button unsichtbar.

Wenn ich im Javacode folgendes schreibe:

*stopButton.setBackgroundResource(android.R.drawable.btn_default);*

Dann sieht der Button sehr gut aus. Diese Darstellung würde ich gerne als Default haben. Ich denke die Darstellung rührt aus meiner styles.xml, kann das sein? dort steht:

<resources xmlns:android="http://schemas.android.com/tools">
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

Nun, was muss ich ändern, damit diese Darstellung, die ich mit dem Java-Befehl umgesetzt habe, Default wird bzw. bleibt und die Buttons runde Ecken erhält? Für die Umsetzung wäre ich sehr dankbar, wenn ich möglichst wenige, neue .XML - Dateien erzeugen muss (für bessere Übersicht und Verständlichkeit).

Vielen Dank !!

Antworten
swa00
  • Forum-Beiträge: 3.704

20.06.2017, 11:36:35 via Website

Hallo Arne,

man kann es auch ein wenig einfacher gestalten.
a) erstelle dir in drawable eine myroundbutton.xml

< shape xmlns:android="http://schemas.android.com/apk/res/android" >
< solid android:color="@android:color/transparent"/ >
< solid android:color="#FFFFFFFF"/ >
/>
< corners android:radius="20.0dip" / >
< stroke
android:width="1dp"
android:color="#88FFFFFF"/ >
< /shape >

Dann hierzu Schnipsel aus meinem Code

public void setRoundedButton (Button btn, int fillcolor, int strokecolor, int textcolor)
{
btn.setBackgroundResource(R.drawable.myroundbutton);
btn.setPadding(0, 0, 0, 0);
btn.setTextColor(textcolor);
btn.setTextSize(16);
btn.setTransformationMethod(null);
btn.setGravity(Gravity.CENTER_HORIZONTAL| Gravity.CENTER_VERTICAL);
btn.setTypeface(FONT);
GradientDrawable bgShapeic = (GradientDrawable)btn.getBackground();
bgShapeic.setColor (fillcolor);
bgShapeic.setStroke(2,strokecolor);
bgShapeic.setCornerRadius((float)50);
}

Aufruf :

Button bt = ( Button) findViewById (....);
setRoundedButton (bt,0xFFFFFFFF, 0xFF000000,0xFFFF0000);
.

Das kannste dann verändern wie du magst :-)

Hier ein paar Screenshots von mir , was das obige bewirkt

https://fscl01.fonpit.de/userfiles/7361302/image/forum/device-2017-06-08-131838.png
.
https://fscl01.fonpit.de/userfiles/7361302/image/forum/device-2017-06-08-131900.png

— geändert am 20.06.2017, 11:45:19

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

Arne

Antworten
Arne
  • Forum-Beiträge: 41

20.06.2017, 14:02:54 via Website

Hey Stefan,

vielen Dank für deine Antwort!

Diese Methode müsste ich quasi zu Beginn für jeden Button, der in der App bzw. in dieser Activity existiert (und dieses Aussehen bekommen soll) anwenden, richtig?

Und wie wäre das nun, wenn ich einem Button ein bestimmtes Image gebe hiermit:

    *Button.setBackgroundResource(R.drawable.button);*

und anschließend es wieder hiermit entferne:

    *Button.setBackgroundResource(android.R.drawable.btn_default);*

bleibt es dann wieder ursprünglich, also Default mit den Änderungen, die ich mit deiner Methode bewirkt habe?

Antworten
swa00
  • Forum-Beiträge: 3.704

20.06.2017, 14:07:45 via Website

Und wie wäre das nun, wenn ich einem Button ein bestimmtes Image gebe hiermit:

Das kannst du gerne Versuchen , wird dich aber beim nächsten Device, welches abstruse
Abmasse hat , gleich wieder auf den Boden der Tatsachen zurück holen :-)

Du kannst dir auch eine Routine bauen , die alle Buttons in deinem Layout automatisch direkt setzt.
Ich muss aber dazu sagen , das man das nicht unbedingt tun soll - das gibt bei vielen ELementen
ein Gehoppel beim Aufruf ( Diashow)

Hier mal ein Beispiel, wie man allen TextViewes den gleichen Font zuweist

public void replaceFonts(ViewGroup viewTree)
{
View child;
for(int i = 0; i < viewTree.getChildCount(); ++i)
{
child = viewTree.getChildAt(i);
if(child instanceof ViewGroup)
{
// recursive call
replaceFonts((ViewGroup)child);
}
else if(child instanceof TextView)
{
// base case
((TextView) child).setTypeface(FONT);
}
}
}

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

ArnePascal P.

Antworten
Arne
  • Forum-Beiträge: 41

20.06.2017, 17:02:13 via Website

Ein Gehoppel würde ich gerne in jedem Fall vermeiden wollen. Ich befürchte aber, dass das evtl. auch mit deiner Methode passieren könnte, wenn ich sie zu Beginn gleich auf 100 Buttons (oder so) anwende.

Ich habe immer noch nicht die Suche nach der einfachen und trivialen Lösung aufgegeben, bei der ich einfach quasi den Default-Wert im Theme (in meiner style.xml oder so) ändere, sodass die Abrundungen einfach zum Normalfall werden und ich mir sonst keine weiteren Gedanken mehr machen muss.

Falls niemand weiß wie das geht, werden ich deine Methode testen und schauen, ob sie in der Lage sind sich von den Image-Änderungen zu erholen (Manche Buttons sollen nämlich (nur) im enabled-Zustand ein anderes Aussehen haben).

Übrigens habe ich mit Abmessungen kein Problem, da es ein skalierbares 9-Patch-image ist.

— geändert am 20.06.2017, 17:03:09

Antworten
swa00
  • Forum-Beiträge: 3.704

20.06.2017, 17:06:12 via Website

Ein 9-patch image ist ja was anderes , als eine Background-Grafik ...

Ich habe immer noch nicht die Suche nach der einfachen und trivialen Lösung aufgegeben, bei der ich einfach quasi den Default-Wert im Theme (in meiner style.xml oder so) ändere, sodass die Abrundungen einfach zum Normalfall werden und ich mir sonst keine weiteren Gedanken mehr machen muss.

Coden ist Fleißsache, da kommst du nicht drumrum.

Und wenn du es vernünftig machen möchtest , dann plane immer 2/3 der Zeit für GUI/UI und
Haptik ein

Manche Buttons sollen nämlich (nur) im enabled-Zustand ein anderes Aussehen haben

Und was spricht dagegen, diese eine einfache Zeile nach meinem Beispiel anzuwenden.
Ob du jetzt diese oder "setBackground..." schreibst - kommt aufs gleiche raus :-)

— geändert am 20.06.2017, 17:08:31

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

Pascal P.Arne

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

20.06.2017, 17:14:05 via Website

Wie wäre es mit einer eigenen ButtonView?
Dann hast du in der Hand, was mit deinem Button passiert und kannst deinen Style direkt setzen?

    public class RoundedButton extends Button{
//Hier musst du halt schauen, wie du von Button erbst und deinen Code in die passende Methode (construktor o.ä,.) schreiben
    ...}

und deine sonderwünsche kannst du da auch reinprogrammieren.

und im XML kannst du das dann einbinden:

<com.myPackage.RoundedButton
---/>

Das macht dies ungemein einfacher finde ich.

So habe ich das bei ImageViews gelößt (wobei die RoundedImageView aus einer Lib kommt).

— geändert am 20.06.2017, 17:15:02

LG Pascal //It's not a bug, it's a feature. :) ;)

Arneswa00

Antworten
Arne
  • Forum-Beiträge: 41

21.06.2017, 12:00:27 via Website

swa00

Ein 9-patch image ist ja was anderes , als eine Background-Grafik ...

Ich habe immer noch nicht die Suche nach der einfachen und trivialen Lösung aufgegeben, bei der ich einfach quasi den Default-Wert im Theme (in meiner style.xml oder so) ändere, sodass die Abrundungen einfach zum Normalfall werden und ich mir sonst keine weiteren Gedanken mehr machen muss.

Coden ist Fleißsache, da kommst du nicht drumrum.

Und wenn du es vernünftig machen möchtest , dann plane immer 2/3 der Zeit für GUI/UI und
Haptik ein

Manche Buttons sollen nämlich (nur) im enabled-Zustand ein anderes Aussehen haben

Und was spricht dagegen, diese eine einfache Zeile nach meinem Beispiel anzuwenden.
Ob du jetzt diese oder "setBackground..." schreibst - kommt aufs gleiche raus :-)

Ja, stimmt. Aber hey, kann ich es nicht sogar noch einfacher machen, indem ich meine Funktion

Button.setBackgroundResource(android.R.drawable.btn_default);

ändere zu:

setRoundedButton(Button);

mit

public void setRoundedButton (Button btn) { 
btn.setBackgroundResource(android.R.drawable.btn_default); 
GradientDrawable bgShapeic = (GradientDrawable)btn.getBackground(); 
bgShapeic.setCornerRadius((float)50); 
}

Denn ich will ja nur die Ecken ändern und den Rest lassen.

— geändert am 21.06.2017, 12:05:41

Antworten
Arne
  • Forum-Beiträge: 41

21.06.2017, 12:10:17 via Website

Pascal P.

Wie wäre es mit einer eigenen ButtonView?
Dann hast du in der Hand, was mit deinem Button passiert und kannst deinen Style direkt setzen?

    public class RoundedButton extends Button{
//Hier musst du halt schauen, wie du von Button erbst und deinen Code in die passende Methode (construktor o.ä,.) schreiben
    ...}

und deine sonderwünsche kannst du da auch reinprogrammieren.

und im XML kannst du das dann einbinden:

<com.myPackage.RoundedButton
---/>

In welcher .XML genau?

Wenn ich das richtig verstanden habe, habe ich dann zwei verschiedene Buttontypen: Button und RoundedButton. Ich ersetze dann quasi überall wo "Button" in der MainActivity.xml und in den Java-Codes durch RoundedButton, richtig?

Antworten
swa00
  • Forum-Beiträge: 3.704

21.06.2017, 12:28:18 via Website

Ja, stimmt. Aber hey, kann ich es nicht sogar noch einfacher machen, indem ich meine Funktion
Button.setBackgroundResource(android.R.drawable.btn_default);
ändere zu:
setRoundedButton(Button);

Ja klar Arne ,

du kannst dir doch jede Funktion schreiben , die dir beliebt ?
(Ich bin jetzt ein wenig verwundert darüber, dass das für dich eine Frage bedeutete)

Ich frage mich allerdings, was NUR ein Aufruf in einer Funktion bewirken soll
(ausser verschwendete CodeZeilen)

Du hattest aber doch ganz oben nach runden Ecken nachgefragt und dazu
habe ich dir die passende Lösung gegeben ...

Kann es sein , dass du noch nicht soooooo ganz verstanden hast , was wir dir
mit unseren Lösungen geschrieben haben ? :-)

— geändert am 21.06.2017, 12:32:31

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

Pascal P.

Antworten
Arne
  • Forum-Beiträge: 41

21.06.2017, 13:02:40 via Website

Ähm Moment, hast du vielleicht diesen Code in meinem letzten Beitrag nicht sehen können?

hier ist er nochmal:

public void setRoundedButton (Button btn) {
btn.setBackgroundResource(android.R.drawable.btn_default);
GradientDrawable bgShapeic = (GradientDrawable)btn.getBackground();
bgShapeic.setCornerRadius((float)50);
}

Ich habe einfach deinen Code genommen und ein paar Zeilen wie Btn.setTextColor(...) usw. entfernt und außerdem als BackgroundResource android.R.drawable.btn_default genommen, weil durch diese der Button schön angezeigt wird (bis auf die eckigen Ecken) und wollte fragen, ob das so legitim ist oder ob dann Eigenschaften fehlen und der Button dann nicht so dargestellt wird, wie ich es mir vorstelle.

Aber das kann ich ja auch selber mal ausprobieren. Ich melde mich...

Antworten
swa00
  • Forum-Beiträge: 3.704

21.06.2017, 13:05:40 via Website

Ähm Moment, hast du vielleicht diesen Code in meinem letzten Beitrag nicht sehen können?

nööö, der war vorher nicht drin , sonst hätte ich ja nicht rumgemotzt :-)
(Die Formatierung hier im Forum ist eh mehr als "Guru" freundlich :-)

Ansonsten : Kommt gut :-)

— geändert am 21.06.2017, 13:06:09

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

Pascal P.

Antworten
Arne
  • Forum-Beiträge: 41

21.06.2017, 13:11:24 via Website

Also wenn ich vorher

btn.setBackgroundResource(android.R.drawable.btn_default);

ausführe, dann stürzt die App bei

GradientDrawable bgShapeic = (GradientDrawable)btn.getBackground();
bgShapeic.setCornerRadius((float)50);

ab.

java.lang.IllegalStateException: Could not execute method for android:onClick
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:293)
at android.view.View.performClick(View.java:5637)
at android.view.View$PerformClick.run(View.java:22429)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288)
at android.view.View.performClick(View.java:5637) 
at android.view.View$PerformClick.run(View.java:22429) 
at android.os.Handler.handleCallback(Handler.java:751) 
at android.os.Handler.dispatchMessage(Handler.java:95) 
at android.os.Looper.loop(Looper.java:154) 
at android.app.ActivityThread.main(ActivityThread.java:6119) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) 
Caused by: java.lang.ClassCastException: android.graphics.drawable.StateListDrawable cannot be cast to android.graphics.drawable.GradientDrawable
at de.geopp.georinexlogger.MainActivity.start(MainActivity.java:790)
at java.lang.reflect.Method.invoke(Native Method) 
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288) 
at android.view.View.performClick(View.java:5637) 
at android.view.View$PerformClick.run(View.java:22429) 
at android.os.Handler.handleCallback(Handler.java:751) 
at android.os.Handler.dispatchMessage(Handler.java:95) 
at android.os.Looper.loop(Looper.java:154) 
at android.app.ActivityThread.main(ActivityThread.java:6119) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) 

Ich teste mal deinen Weg...

Antworten
swa00
  • Forum-Beiträge: 3.704

21.06.2017, 13:16:16 via Website

Also wenn ich vorher
btn.setBackgroundResource(android.R.drawable.btn_default);
ausführe, dann stürzt die App bei

RICHTIG : - Denn

android.R.drawable.btn_default beinhaltet NICHT die erforderlichen Shapes, die du verändern möchtest

Deshalb habe ich dir oben geschrieben :
Erstelle EINMALIG die "pseudo" myroundbutton.xml von mir und verwende die

— geändert am 21.06.2017, 14:05:17

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

Pascal P.Arne

Antworten
Arne
  • Forum-Beiträge: 41

21.06.2017, 14:50:49 via Website

swa00

Also wenn ich vorher
btn.setBackgroundResource(android.R.drawable.btn_default);
ausführe, dann stürzt die App bei

RICHTIG : - Denn

android.R.drawable.btn_default beinhaltet NICHT die erforderlichen Shapes, die du verändern möchtest

Deshalb habe ich dir oben geschrieben :
Erstelle EINMALIG die "pseudo" myroundbutton.xml von mir und verwende die

Wie und wo hast du die Variable FONT in btn.setTypeface(); definiert?

Wenn ich richtig vermute, würden die Default-buttons auf diesem Weg später nicht aussehen wie android.R.drawable.btn_default , richtig? Default-mäßig sehen die Buttons nämlich langweilig, also nur grau aus (rührt von dem Theme das ich benutze). Erst wenn ich den Background source auf android.R.drawable.btn_default setze, erhält er das gewünschte Aussehen, mit eckigen Klammern. Muss ich nicht in der button-XML von dir eine Vererbung von android.R.drawable.btn_default einbringen, damit auch dieses Aussehen übernommen wird?

Antworten
swa00
  • Forum-Beiträge: 3.704

21.06.2017, 15:11:38 via Website

FONT ist bei mir in einer SingleTon Klasse definiert und kommt global.
Sollte dir also nur als Veranschaulichung dienen.

Vererben kannst du es nicht -
Du kannst aber dir das Aussehen frei gestalten - so wie du das möchtest .
Dafür änderst du den Inhalt der myround.xml - oder erstellst dir halt selbst eine

Da ist alles offen , was das Herz begehrt.
Oder du machst halt was mit Übergabe-Parameter , so wie ich dir oben gezeigt habe

Wichtig ist nur :
Möchtest du während der Laufzeit Parameter ändern , so müssen diese Parameter auch
in der xml definiert sein , sonst kommt es halt zu deinem Absturz

Du wirst also nicht drumrum kommen , dich mit der Materie genauer auseinander
zu setzen ... Wie es geht , weisst du ja jetzt

— geändert am 21.06.2017, 15:14:08

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

Pascal P.Arne

Antworten
Arne
  • Forum-Beiträge: 41

21.06.2017, 16:03:11 via Website

Okay ich befürchte, dass das, was ich vor hatte, grundsätzlich nicht möglich war/ist.

Ich wollte die btn_default bzw. die Buttons aus Widget.AppCompat.Light.ActionBar verwenden, und zwar mit abgerundeten Buttons, da sie ziemlich eckig sind und mir das nicht gefällt.

Während man in Android Studio recht gut und einfach eigene Buttonstyles designed und anwenden kann, ist es wohl nicht vorgesehen, dass man bestehende Buttonstyles übernimmt und modifiziert. Zumindest ist es mir in 2 Tagen nicht gelungen.

Antworten
swa00
  • Forum-Beiträge: 3.704

21.06.2017, 16:34:16 via Website

Na es hat schon seinen Grund , warum wir diese Version von Ergebnis präsentieren . :-)

Sieht alles so locker-flockig aus - Aber hinter so einer Antwort stecken oft etliche Tage an Arbeit und Verzweiflung :-)

— geändert am 22.06.2017, 10:06:03

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

Arne

Antworten