Comment puis-je réduire le dessinable sur un bouton?

87

comment puis-je rendre le dessin sur un bouton plus petit? L'icône est trop grande, en fait plus haute que le bouton. Voici le code que j'utilise:

    <Button
    android:background="@drawable/red_button"
    android:drawableLeft="@drawable/s_vit"
    android:id="@+id/ButtonTest"
    android:gravity="left|center_vertical" 
    android:text="S-SERIES CALCULATOR"
    android:textColor="@android:color/white"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:layout_marginLeft="25dp"
    android:layout_marginRight="25dp"
    android:drawablePadding="10dp">
    </Button>

Le haut est à quoi il devrait ressembler, le bas à quoi il ressemble maintenant.

Le haut est à quoi il devrait ressembler, le bas à quoi il ressemble maintenant.

J'ai essayé cela mais aucune image n'est affichée. :-(

    Resources res = getResources();
    ScaleDrawable sd = new ScaleDrawable(res.getDrawable(R.drawable.s_vit), 0, 10f, 10f);
    Button btn = (Button) findViewById(R.id.ButtonTest);
    btn.setCompoundDrawables(sd.getDrawable(), null, null, null);
Reto
la source
Ce serait mieux si vous téléchargez une image de ce que vous obtenez et de ce que vous essayez de faire. Merci.
Lalit Poptani
Vous pouvez définir votre bouton personnalisé afin de définir la taille des dessinables. Voir ma réponse ici stackoverflow.com/a/31916731/2308720
Oleksandr
Je sais que cela date de 2011 ... mais je préfère en fait l'apparence du bouton avec la caméra sortant des limites du bouton - je l'aurais laissé tel quel ... il suffit de dire :)
killercowuk

Réponses:

70

Vous devez utiliser un ImageButton et spécifier l'image dans android:src, et définir android:scaletypesurfitXY


Définition de la mise à l'échelle dessinable dans le code

Drawable drawable = getResources().getDrawable(R.drawable.s_vit);
drawable.setBounds(0, 0, (int)(drawable.getIntrinsicWidth()*0.5), 
                         (int)(drawable.getIntrinsicHeight()*0.5));
ScaleDrawable sd = new ScaleDrawable(drawable, 0, scaleWidth, scaleHeight);
Button btn = findViewbyId(R.id.yourbtnID);
btn.setCompoundDrawables(sd.getDrawable(), null, null, null); //set drawableLeft for example
Ronnie
la source
Si vous définissez le dessinable dans le code, vous pouvez le redimensionner en fonction de la hauteur du bouton, puis le définir.
Ronnie
Maintenant, l'image est affichée mais elle n'est pas redimensionnée! J'ai essayé des valeurs entre 0,1f et 10f. Une idée? Merci pour votre aide ...
Reto
Essayez cecidrawable.setBounds(0, 0, drawable.getIntrinsicWidth()*0.5, drawable.getIntrinsicHeight()*0.5);
Ronnie
Si cela redimensionne le dessinable, vous pouvez supprimer la partie dessinable à l'échelle et utiliser directement le dessinable.
Ronnie
2
Sommes-nous censés définir nos propres valeurs pour scaleWidth et scaleHeight? Sont-ils simplement descriptifs?
SametSahin
89

J'ai trouvé une solution XML très simple et efficace qui ne nécessite pas ImageButton

Créez un fichier dessinable pour votre image comme ci-dessous et utilisez-le pour android:drawableLeft

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item
    android:id="@+id/half_overlay"
    android:drawable="@drawable/myDrawable"
    android:width="40dp"
    android:height="40dp"
    />

</layer-list>

Vous pouvez définir la taille de l'image avec android:widthet android:heightpropriétés.

De cette façon, vous pouvez au moins obtenir la même taille pour différents écrans.

L'inconvénient est que ce n'est pas exactement comme fitXY qui redimensionnerait la largeur de l'image pour s'adapter à X et redimensionnerait la hauteur de l'image en conséquence.

Copain
la source
9
Cela devrait être la réponse acceptée. Si l'on ne veut pas d'ImageButton (par exemple parce qu'ils veulent du texte, etc.) alors cette réponse permet des images de taille dans un Button avec du texte plus zéro code.
Acier recyclé
3
J'ai créé un nouveau dessinable comme celui-ci, puis android:drawableTopj'ai ajouté le nouveau dessinable. Quelles que soient les valeurs de largeur / hauteur que j'ai définies, cela me montre celle par défaut.
driftking9987
9
Ne semble pas fonctionner pour les versions Android inférieures à Lollipop.
Jyotman Singh
32
la hauteur et la largeur ne fonctionnent que dans l'API de niveau 23 et supérieur. Non pris en charge à l'envers.
Palak Darji
Je suis d'accord, c'est de loin la meilleure solution
Senzo Malinga
10

Les boutons ne redimensionnent pas leurs images internes.

Ma solution ne nécessite pas de manipulation de code.

Il utilise une mise en page avec TextView et ImageView.

L'arrière-plan de la mise en page doit avoir le dessin 3D rouge.

Vous devrez peut-être définir l' attribut android: scaleType xml.

Exemple:

<LinearLayout
    android:id="@+id/list_item"
    android:layout_width="fill_parent"
    android:layout_height="50dp"
    android:padding="2dp" >

    <ImageView
        android:layout_width="50dp"
        android:layout_height="fill_parent"
        android:src="@drawable/camera" />

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1"
        android:lines="1"
        android:gravity="center_vertical"
        android:text="Hello - primary" />

</LinearLayout>

BTW:

  1. Le fait de compter sur des icônes de résolution différentes peut entraîner une interface utilisateur non prévisible (icône trop grande ou trop petite)
  2. Le texte dans la vue de texte (y compris dans les boutons) ne remplit pas le composant. C'est un problème Android et je ne sais pas comment le résoudre.
  3. Vous pouvez l'utiliser comme une inclusion.

Bonne chance

AlikElzin-kilaka
la source
RE: TextViews, si je veux que la vue soit aussi petite que possible, je mets le remplissage à zéro. Sinon, il semble avoir un remplissage par défaut.
William T.Mallard
6

Utilisez un ScaleDrawable comme Abhinav l'a suggéré.

Le problème est que le dessinable ne s'affiche pas alors - c'est une sorte de bogue dans ScaleDrawables. vous devrez changer le "niveau" par programme. Cela devrait fonctionner pour chaque bouton:

// Fix level of existing drawables
Drawable[] drawables = myButton.getCompoundDrawables();
for (Drawable d : drawables) if (d != null && d instanceof ScaleDrawable) d.setLevel(1);
myButton.setCompoundDrawables(drawables[0], drawables[1], drawables[2], drawables[3]);
zeh
la source
Agréable. Je pense que je pourrais utiliser ceci dans un proche avenir!
Abhinav
@zeh, maintenant j'ai trouvé que cela fonctionne si vous exécutez le code ci-dessus avant setContentView, sinon cela ne fonctionne pas. Cela pourrait être mieux si vous ajoutez ceci à votre message.
Buddy
Pour une raison quelconque, ma solution ci-dessus ne fonctionne pas sur toutes les versions d'Android.
Buddy
6

Mon DiplayScaleHelper, qui fonctionne parfaitement:

import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ScaleDrawable;
import android.widget.Button;

public class DisplayHelper {

  public static void scaleButtonDrawables(Button btn, double fitFactor) {
        Drawable[] drawables = btn.getCompoundDrawables();

        for (int i = 0; i < drawables.length; i++) {
            if (drawables[i] != null) {
                if (drawables[i] instanceof ScaleDrawable) {
                    drawables[i].setLevel(1);
                }
                drawables[i].setBounds(0, 0, (int) (drawables[i].getIntrinsicWidth() * fitFactor),
                    (int) (drawables[i].getIntrinsicHeight() * fitFactor));
                ScaleDrawable sd = new ScaleDrawable(drawables[i], 0, drawables[i].getIntrinsicWidth(), drawables[i].getIntrinsicHeight());
                if(i == 0) {
                    btn.setCompoundDrawables(sd.getDrawable(), drawables[1], drawables[2], drawables[3]);
                } else if(i == 1) {
                    btn.setCompoundDrawables(drawables[0], sd.getDrawable(), drawables[2], drawables[3]);
                } else if(i == 2) {
                    btn.setCompoundDrawables(drawables[0], drawables[1], sd.getDrawable(), drawables[3]);
                } else {
                    btn.setCompoundDrawables(drawables[0], drawables[1], drawables[2], sd.getDrawable());
                }
            }
        }
    }
}
Владимир Фишер
la source
4

Vous pouvez faire appel setBoundsaux dessinables "composés" pour modifier la taille de l'image.

Essayez ce code pour dimensionner automatiquement le dessinable de votre bouton:

DroidUtils.scaleButtonDrawables((Button) findViewById(R.id.ButtonTest), 1.0);

défini par cette fonction:

public final class DroidUtils {

    /** scale the Drawables of a button to "fit"
     *  For left and right drawables: height is scaled 
     *  eg. with fitFactor 1 the image has max. the height of the button.
     *  For top and bottom drawables: width is scaled: 
     *  With fitFactor 0.9 the image has max. 90% of the width of the button 
     *  */
    public static void scaleButtonDrawables(Button btn, double fitFactor) {
        Drawable[] drawables = btn.getCompoundDrawables();

        for (int i = 0; i < drawables.length; i++) {
            if (drawables[i] != null) {
                int imgWidth = drawables[i].getIntrinsicWidth();
                int imgHeight = drawables[i].getIntrinsicHeight();
                if ((imgHeight > 0) && (imgWidth > 0)) {    //might be -1
                    float scale;
                    if ((i == 0) || (i == 2)) { //left or right -> scale height
                        scale = (float) (btn.getHeight() * fitFactor) / imgHeight;
                    } else { //top or bottom -> scale width
                        scale = (float) (btn.getWidth() * fitFactor) / imgWidth;                    
                    }
                    if (scale < 1.0) {
                        Rect rect = drawables[i].getBounds();
                        int newWidth = (int)(imgWidth * scale);
                        int newHeight = (int)(imgHeight * scale);
                        rect.left = rect.left + (int)(0.5 * (imgWidth - newWidth)); 
                        rect.top = rect.top + (int)(0.5 * (imgHeight - newHeight));
                        rect.right = rect.left + newWidth;
                        rect.bottom = rect.top + newHeight;
                        drawables[i].setBounds(rect);
                    }
                }
            }
        }
    }
}

Sachez que cela peut ne pas être appelé dans onCreate()une activité, car la hauteur et la largeur du bouton ne sont pas (encore) disponibles ici. Appelez-le onWindowFocusChanged()ou utilisez cette solution pour appeler la fonction.

Édité:

La première incarnation de cette fonction n'a pas fonctionné correctement. Il a utilisé le code userSeven7s pour redimensionner l'image, mais le retour ScaleDrawable.getDrawable() ne semble pas fonctionner (ni le retour ScaleDrawable) pour moi.

Le code modifié utilise setBoundspour fournir les limites de l'image. Android adapte l'image dans ces limites.

yonojoy
la source
Merci d'avoir dit de ne pas l'appeler onCreate().
Binarian
1

Je le fais comme ci-dessous. Cela crée une image de taille 100x100 dans le bouton indépendamment de l'image d'entrée.

drawable.bounds = Rect(0,0,100,100)
button.setCompoundDrawables(drawable, null, null, null)

Ne pas utiliser ScaleDrawablenon plus. Ne pas utiliser a button.setCompoundDrawablesRelativeWithIntrinsicBounds()résolu mon problème, car cela semble utiliser des limites intrinsèques (taille de l'image source) au lieu des limites que vous venez de définir.

LP
la source
0

Vous pouvez utiliser des tableaux de tailles différentes qui sont utilisés avec différentes densités / tailles d'écran, etc. afin que votre image soit parfaite sur tous les appareils.

Voir ici: http://developer.android.com/guide/practices/screens_support.html#support

HXCaïne
la source
J'utilise la même image à différents endroits. C'est pourquoi je ne peux pas le redimensionner, il doit être affiché dans la taille que je souhaite.
Reto le
0

Avez-vous essayé d' encapsuler votre image dans un ScaleDrawable , puis de l'utiliser dans votre bouton?

Abhinav
la source
2
Je viens d'essayer ceci, mais mon ScaleDrawable ne s'affiche pas. :-( Même pas dans un ImageView. J'ai pris l'exemple de code et je viens de remplacer le dessinable. Une idée de la raison pour laquelle cela ne fonctionne pas?
Reto
J'ai eu le même problème. ScaleDrawableserait parfait, mais cela ne fonctionne tout simplement pas. Cela semble avoir quelque chose à voir avec les «niveaux». Plus d'informations ici (et quelques solutions de contournement qui sont loin d'être parfaites): stackoverflow.com/questions/5507539/…
zeh
(modifier) ​​l'a corrigé avec du code générique! Solution ici qui vous permet toujours d'utiliser ScaleDrawables: stackoverflow.com/a/13706836/439026
zeh
0

Voici la fonction que j'ai créée pour mettre à l'échelle les dessins vectoriels. Je l'ai utilisé pour définir TextView composé dessiné.

/**
 * Used to load vector drawable and set it's size to intrinsic values
 *
 * @param context Reference to {@link Context}
 * @param resId   Vector image resource id
 * @param tint    If not 0 - colour resource to tint the drawable with.
 * @param newWidth If not 0 then set the drawable's width to this value and scale 
 *                 height accordingly.
 * @return On success a reference to a vector drawable
 */
@Nullable
public static Drawable getVectorDrawable(@NonNull Context context,
                                         @DrawableRes int resId,
                                         @ColorRes int tint,
                                         float newWidth)
{
    VectorDrawableCompat drawableCompat =
            VectorDrawableCompat.create(context.getResources(), resId, context.getTheme());
    if (drawableCompat != null)
    {
        if (tint != 0)
        {
            drawableCompat.setTint(ResourcesCompat.getColor(context.getResources(), tint, context.getTheme()));
        }

        drawableCompat.setBounds(0, 0, drawableCompat.getIntrinsicWidth(), drawableCompat.getIntrinsicHeight());

        if (newWidth != 0.0)
        {
            float scale = newWidth / drawableCompat.getIntrinsicWidth();
            float height = scale * drawableCompat.getIntrinsicHeight();
            ScaleDrawable scaledDrawable = new ScaleDrawable(drawableCompat, Gravity.CENTER, 1.0f, 1.0f);
            scaledDrawable.setBounds(0,0, (int) newWidth, (int) height);
            scaledDrawable.setLevel(10000);
            return scaledDrawable;
        }
    }
    return drawableCompat;
}
zmicer
la source
0
  • En utilisant la fonction "IMPORTER PAR BATCH DRAWABLE", vous pouvez importer une taille personnalisée en fonction de vos besoins, exemple 20dp * 20dp

    • Maintenant, après l'importation, utilisez l'image drawable_image importée comme drawable_source pour votre bouton

    • C'est plus simple comme ça entrez la description de l'image ici

Santhosh PR
la source
Comment êtes-vous arrivé là?
développeur android
0

C'est parce que vous ne l'avez pas fait setLevel. après vous setLevel(1), il sera affiché comme vous le souhaitez

Songtao Lou
la source
0

Utilisation de l'extension Kotlin

val drawable = ContextCompat.getDrawable(context, R.drawable.my_icon)
// or resources.getDrawable(R.drawable.my_icon, theme)
val sizePx = 25
drawable?.setBounds(0, 0, sizePx, sizePx)
//                            (left,     top,  right, bottom)
my_button.setCompoundDrawables(drawable, null, null, null)

Je suggère de créer une fonction d'extension sur TextView ( Button l'étend ) pour une réutilisation facile.

button.leftDrawable(R.drawable.my_icon, 25)

// Button extends TextView
fun TextView.leftDrawable(@DrawableRes id: Int = 0, @DimenRes sizeRes: Int) {
    val drawable = ContextCompat.getDrawable(context, id)
    val size = context.resources.getDimensionPixelSize(sizeRes)
    drawable?.setBounds(0, 0, size, size)
    this.setCompoundDrawables(drawable, null, null, null)
}
Gibolt
la source
La question concernait Button, pas TextView.
Firzen
1
Vous devriez avoir lu la réponse. Un Button étend TextView, vous pouvez donc l'utiliser pour les deux. Ou changez l'extension pour ne prolonger qu'un bouton
Gibolt
-1

J'ai essayé les techniques de cet article mais je n'ai trouvé aucune d'entre elles aussi attrayante. Ma solution consistait à utiliser une vue d'image et une vue de texte et d'aligner la vue d'image en haut et en bas à la vue de texte. De cette façon, j'ai obtenu le résultat souhaité. Voici un code:

<RelativeLayout
    android:id="@+id/relativeLayout1"
    android:layout_width="match_parent"
    android:layout_height="48dp" >


    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignTop="@+id/textViewTitle"
        android:layout_alignBottom="@+id/textViewTitle"
        android:src="@drawable/ic_back" />

    <TextView
        android:id="@+id/textViewBack"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/textViewTitle"
        android:layout_alignBottom="@+id/textViewTitle"
        android:layout_toRightOf="@+id/imageView1"
        android:text="Back"
        android:textColor="@color/app_red"
        android:textSize="@dimen/title_size" />
</RelativeLayout>
Argument illégal
la source
-1

J'ai créé une classe de boutons personnalisée pour y parvenir.

CustomButton.java

public class CustomButton extends android.support.v7.widget.AppCompatButton {

    private Drawable mDrawable;

    public CustomButton(Context context, AttributeSet attrs) {
        super(context, attrs);

        TypedArray a = context.getTheme().obtainStyledAttributes(
                attrs,
                R.styleable.CustomButton,
                0, 0);

        try {
            float mWidth = a.getDimension(R.styleable.CustomButton_drawable_width, 0);
            float mHeight = a.getDimension(R.styleable.CustomButton_drawable_width, 0);

            Drawable[] drawables = this.getCompoundDrawables();
            Drawable[] resizedDrawable = new Drawable[4];

            for (int i = 0; i < drawables.length; i++) {
                if (drawables[i] != null) {
                    mDrawable = drawables[i];
                }
                resizedDrawable[i] = getResizedDrawable(drawables[i], mWidth, mHeight);
            }

            this.setCompoundDrawables(resizedDrawable[0], resizedDrawable[1], resizedDrawable[2], resizedDrawable[3]);
        } finally {
            a.recycle();
        }
    }

    public Drawable getmDrawable() {
        return mDrawable;
    }

    private Drawable getResizedDrawable(Drawable drawable, float mWidth, float mHeight) {
        if (drawable == null) {
            return null;
        }

        try {
            Bitmap bitmap;

            bitmap = Bitmap.createBitmap((int)mWidth, (int)mHeight, Bitmap.Config.ARGB_8888);

            Canvas canvas = new Canvas(bitmap);
            drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
            drawable.draw(canvas);
            return drawable;
        } catch (OutOfMemoryError e) {
            // Handle the error
            return null;
        }
    }
}

attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CustomButton">
        <attr name="drawable_width" format="dimension" />
        <attr name="drawable_height" format="dimension" />
    </declare-styleable>
</resources>

Utilisation en xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="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="com.example.MainActivity">

     <com.example.CustomButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:drawableTop="@drawable/ic_hero"
            android:text="Avenger"
            custom:drawable_height="10dp"
            custom:drawable_width="10dp" />

</RelativeLayout>
Jeffy Lee
la source
1
Pourquoi créez-vous un Canvasin getResizedDrawableet dessinez-vous dedans si vous n'allez rien faire avec? La fonction entière pourrait être réduite à drawable.setBounds(0, 0, mWidth, mHeight).
Antimonit