web-dev-qa-db-fra.com

Android, la définition de la couleur d'arrière-plan du bouton perd son effet d'entraînement

Après avoir ajouté de la couleur à un bouton Android, il perd son effet d'entraînement qui donne à l'utilisateur l'impression qu'il y a un clic réactif. Comment résoudre ce problème? J'ai cherché dans de nombreuses solutions mais je ne pouvais pas n'en trouve pas un qui ne soit pas ambigu.

<RelativeLayout 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"
                tools:context=".ClockInOutFragment">


    <AnalogClock
        Android:id="@+id/clock"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_alignParentEnd="true"
        Android:layout_alignParentRight="true"
        Android:layout_alignParentTop="true"
        Android:layout_toRightOf="@+id/date_and_time"/>


    <RelativeLayout
        Android:id="@+id/date_and_time"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_margin="10dp">

        <TextView
            Android:id="@+id/time_digits"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:text="12:10"
            Android:textSize="45sp"/>

        <TextView
            Android:id="@+id/am_pm"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:layout_alignBaseline="@+id/time_digits"
            Android:layout_toRightOf="@+id/time_digits"
            Android:paddingLeft="3dp"
            Android:text="PM"
            Android:textSize="20sp"/>

        <TextView
            Android:id="@+id/date"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:layout_below="@+id/time_digits"
            Android:text="Mon, July 11"
            Android:textSize="22sp"/>
    </RelativeLayout>

    <!--Clock in and out buttons-->
    <LinearLayout
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:layout_alignParentBottom="true"
        Android:layout_centerHorizontal="true"
        Android:orientation="horizontal">

        <Button
            Android:id="@+id/textView3"
            Android:layout_width="0dp"
            Android:layout_height="56dp"
            Android:layout_weight="1"
            Android:background="#4CAF50"
            Android:gravity="center"
            Android:text="Clock In"
            Android:textAppearance="?android:attr/textAppearanceLarge"
            Android:textColor="#FFFFFF"/>

        <!--Divider between the clock in and out button-->
        <View
            Android:layout_width="1dp"
            Android:layout_height="match_parent"
            Android:background="#B6B6B6"/>

        <Button
            Android:id="@+id/textView4"
            Android:layout_width="0dp"
            Android:layout_height="56dp"
            Android:layout_weight="1"
            Android:background="#FF5252"
            Android:gravity="center"
            Android:text="Clock Out"
            Android:textAppearance="?android:attr/textAppearanceLarge"
            Android:textColor="#FFFFFF"/>
    </LinearLayout>


</RelativeLayout>
20
Tommy Saechao

Vous pouvez ajouter l'effet d'ondulation et la couleur d'arrière-plan avec une ondulation supplémentaire pouvant être dessinée:

votre mise en page:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:orientation="vertical" Android:layout_width="match_parent"
    Android:layout_height="match_parent">

    <Button
        Android:id="@+id/button_connect"
        Android:layout_width="fill_parent"
        Android:layout_height="wrap_content"
        Android:layout_marginTop="20dip"
        Android:fontFamily="sans-serif"
        Android:text="Connect"
        Android:background="@drawable/ripple"
        Android:textColor="#FFFFFF"
        Android:textSize="18sp" />

</LinearLayout>

ripple.xml (c'est ici que vous pouvez ajouter une couleur d'arrière-plan en plus de l'effet d'entraînement):

<?xml version="1.0" encoding="utf-8"?>
<!-- in drawable folder-->
<ripple
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:color="?android:colorControlHighlight">

    <item Android:id="@Android:id/mask">
        <shape Android:shape="rectangle">
            <solid Android:color="?android:colorAccent" />
        </shape>
    </item>

    <item>
        <shape Android:shape="rectangle">
            <!-- put your background color here-->
            <solid Android:color="@color/default_color" />
        </shape>
    </item>

</ripple>
28
Bertrand Martel

Une manière très simple et directe de procéder consiste à définir ?attr/selectableItemBackground à Android:foreground attribut de votre bouton. Le XML suivant est parfaitement valide et fonctionne

<Button
    Android:id="@+id/btn"
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:background="@Android:color/white"
    Android:foreground="?attr/selectableItemBackground"/>
26
Abhishek Bansal

Ne changez pas l'arrière-plan de Button. Changez le thème.

<style name="ButtonGray">
    <item name="colorButtonNormal">@color/gray</item>
</style>

et dans votre fichier xml

<Button
     Android:id="@+id/accept_button"
     Android:layout_height="wrap_content"
     Android:layout_width="0dp"
     Android:layout_weight="1"
     Android:text="@string/button_accept_group"
     Android:theme="@style/ButtonGray"/>

Ou vous pouvez l'ajouter dans votre thème d'application principal

<style name="AppTheme"
           parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorButtonNormal">@color/primary_color</item>
</style>

Et pas besoin de changer l'arrière-plan du bouton.

Si vous voulez un arrière-plan totalement personnalisé, vous devez créer votre sélecteur. Et vous pouvez y définir un effet d'entraînement.

14
thealeksandr

Utilisez simplement:

Android:backgroundTint="#4CAF50"

Au lieu de:

Android:background="#4CAF50"

N'oubliez pas de changer votre Button en Android.support.v7.widget.AppCompatButton

4
Gilad Shapira

En fait, vous pouvez utiliser <layer-list> De dessinables pour combiner l'effet d'entraînement avec tout autre dessinable. C'est une solution universelle également pour le pré-lolipop: je l'ai testé dans de nombreuses configurations.

Le seul problème est que pré-lolipop se bloque lorsque ?selectableItemBackground Apparaît à l'intérieur de <layer-list>, Nous devons donc créer LayerDrawable par programmation.

Une solution simple très rapide ressemble à:

Spécifiez pour votre vue

Android:background="?selectableItemBackground"

Puis, n'importe où dans le code, créez mySpecialDrawable et faites l'astuce:

Drawable[] layers = {mySpecialDrawable, getBackground()};
setBackgroundDrawable(new LayerDrawable(layers).mutate()); 

Veuillez noter que .mutate() pour LayeredDrawable est essentiel ici!

Une solution plus complexe pourrait être utile lorsque vous avez déjà votre vue personnalisée et que vous préférez étendre ses fonctionnalités et sa compatibilité plutôt que d'ajouter FrameLayout vide en tant que parent.

Dans attrs.xml, mettez:

<resources>
    <declare-styleable name="MyView">
        <attr name="selectableBackground" format="reference"/>
        <attr name="backgroundDrawable" format="reference"/>
    </declare-styleable>
</resources>

puis à l'intérieur de votre classe View-descendant:

private Drawable selectableBackground;
private Drawable backgroundDrawable;

public MyView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);

    try {
        TypedArray attributeArray;
        attributeArray = context.obtainStyledAttributes(attrs, R.styleable.MyView);

        int id = attributeArray.getResourceId(R.styleable.MyView_selectableBackground, -1);
        if (id != -1) {
            selectableBackground = ResourcesCompat.getDrawable(getResources(), id, context.getTheme());
        }
        id = attributeArray.getResourceId(R.styleable.MyView_backgroundDrawable, -1);
        if (id != -1) {
            backgroundDrawable = ResourcesCompat.getDrawable(getResources(), id, context.getTheme());
        }

        constructBackground();
        attributeArray.recycle();
    } catch (Exception e) {
        Log.e(this.toString(), "Attributes initialization error", e);
        throw e;
    }
}

void setSelectableBackground(Drawable drawable) {
    selectableBackground = drawable;
    constructBackground();
}

void setDrawable(Drawable drawable) {
    backgroundDrawable = drawable;
    constructBackground();
}

private void constructBackground() {
    if (selectableBackground != null) {
        if (backgroundDrawable != null) {
            Drawable[] layers = {backgroundDrawable, selectableBackground};
            setBackgroundDrawable(new LayerDrawable(layers).mutate());      // Both, using layers
        } else setBackgroundDrawable(selectableBackground);                 // Selectable only
    } else setBackgroundDrawable(backgroundDrawable);                       // Background only or null
}

Je préfère cette approche car elle n'a pas de problème comme l'attribut Android:foreground Qui est 23+ ou une surcharge supplémentaire pour inclure des vues cliquables dans FrameLayout.

0
apc