Come posso ridurre il disegnabile su un pulsante?


87

come posso rendere più piccolo il disegnabile su un pulsante? L'icona è troppo grande, in realtà più alta del pulsante. Questo è il codice che sto usando:

    <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>

La parte superiore è come dovrebbe apparire, quella inferiore come appare in questo momento.

La parte superiore è come dovrebbe apparire, quella inferiore come appare in questo momento.

Ho provato questo ma non viene visualizzata alcuna immagine. :-(

    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);

Sarebbe meglio se caricassi un'immagine di ciò che stai ottenendo e di ciò che stai cercando di fare. Grazie.
Lalit Poptani

È possibile definire il pulsante personalizzato per definire la dimensione dei drawables. Vedi la mia risposta qui stackoverflow.com/a/31916731/2308720
Oleksandr

So che è del 2011 ... ma in realtà preferisco l'aspetto del pulsante con la fotocamera che supera i limiti del pulsante - l'avrei lasciato com'era ... solo dicendo :)
killercowuk

Risposte:


70

È necessario utilizzare un ImageButton e specificare l'immagine in android:srce impostare android:scaletypesufitXY


Impostazione disegnabile in scala nel codice

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

Se imposti il ​​disegnabile nel codice, puoi ridimensionarlo in base all'altezza del pulsante e quindi impostarlo.
Ronnie

Ora l'immagine viene visualizzata ma non viene ridimensionata! Ho provato valori compresi tra 0.1f e 10f. Qualche idea? Grazie per il vostro aiuto ...
Reto

Prova questodrawable.setBounds(0, 0, drawable.getIntrinsicWidth()*0.5, drawable.getIntrinsicHeight()*0.5);
Ronnie

Se questo ridimensiona il disegno, è possibile rimuovere la parte ridimensionabile e utilizzare direttamente il disegno.
Ronnie

2
Dobbiamo impostare i nostri valori per scaleWidth e scaleHeight? Sono solo descrittivi?
SametSahin

89

Ho trovato una soluzione XML molto semplice ed efficace che non richiede ImageButton

Crea un file disegnabile per la tua immagine come di seguito e usalo per 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>

È possibile impostare la dimensione dell'immagine con android:widtheandroid:height proprietà.

In questo modo potresti almeno ottenere la stessa dimensione per schermi diversi.

Lo svantaggio è che non è esattamente come fitXY che ridimensionerebbe la larghezza dell'immagine per adattarla a X e ridimensionerebbe l'altezza dell'immagine di conseguenza.


9
Questa dovrebbe essere la risposta accettata. Se non si desidera un ImageButton (ad es. Perché vogliono del testo, ecc.), Questa risposta consente immagini di dimensioni all'interno di un pulsante con testo più codice zero.
Acciaio riciclato

3
Ho creato un nuovo disegnabile come questo e poi android:drawableTopho aggiunto il nuovo disegnabile. Indipendentemente dai valori impostati per la larghezza / altezza, mi mostra quello predefinito.
driftking9987

9
Non sembra funzionare per le versioni Android inferiori a Lollipop.
Jyotman Singh

32
altezza, larghezza funzionano solo nel livello API 23 e superiore. Non supportato all'indietro.
Palak Darji

Sono d'accordo, questa è di gran lunga la soluzione migliore
Senzo Malinga

10

I pulsanti non ridimensionano le immagini interne.

La mia soluzione non richiede la manipolazione del codice.

Utilizza un layout con TextView e ImageView.

Lo sfondo del layout dovrebbe avere il disegno 3d rosso.

Potrebbe essere necessario definire l' attributo xml android: scaleType .

Esempio:

<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. Il conteggio su icone di risoluzione diverse può causare un'interfaccia utente non prevedibile (icona troppo grande o troppo piccola)
  2. Il testo nella visualizzazione testo (inclusi i pulsanti) non riempie il componente. Questo è un problema Android e non so come risolverlo.
  3. Puoi usarlo come inclusione.

In bocca al lupo


RE: TextViews, se voglio che la vista sia il più piccola possibile, imposto il riempimento a zero. Altrimenti sembra avere un'imbottitura predefinita.
William T. Mallard

6

Usa un ScaleDrawable come suggerito da Abhinav .

Il problema è che il drawable non viene visualizzato, è una sorta di bug in ScaleDrawables. dovrai modificare il "livello" a livello di programmazione. Questo dovrebbe funzionare per ogni pulsante:

// 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]);

Bello. Penso che potrei usarlo nel prossimo futuro!
Abhinav

@zeh, ora ho scoperto che funziona se esegui il codice sopra prima di setContentView, altrimenti non funziona. Potrebbe essere meglio se lo aggiungi al tuo post.
Buddy

Per qualche motivo, la mia soluzione di cui sopra non funziona su tutte le versioni di Android.
Buddy

6

Il mio DiplayScaleHelper, che funziona perfettamente:

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());
                }
            }
        }
    }
}

4

Puoi chiamare setBounds i drawables "composti" per modificare la dimensione dell'immagine.

Prova questo codice per ridimensionare automaticamente il disegnabile del tuo pulsante:

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

definito da questa funzione:

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);
                    }
                }
            }
        }
    }
}

Tieni presente che questo potrebbe non essere chiamato in onCreate()un'attività, perché l'altezza e la larghezza dei pulsanti non sono (ancora) disponibili lì. Chiamalo attivo onWindowFocusChanged()o usa questa soluzione per chiamare la funzione.

Modificato:

La prima incarnazione di questa funzione non ha funzionato correttamente. Ha usato il codice userSeven7s per ridimensionare l'immagine, ma il ritorno ScaleDrawable.getDrawable() non sembra funzionare (né il ritornoScaleDrawable ) per me.

Il codice modificato viene utilizzato setBoundsper fornire i limiti per l'immagine. Android adatta l'immagine in questi limiti.


Grazie per aver detto di non chiamarlo onCreate().
Binarian


1

Lo sto facendo come sotto. Questo crea un'immagine di dimensioni 100x100 nel pulsante indipendentemente dall'immagine in ingresso.

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

Non lo uso ScaleDrawableneanche. Non usare ha button.setCompoundDrawablesRelativeWithIntrinsicBounds()risolto il mio problema, in quanto sembra utilizzare limiti intrinseci (dimensione dell'immagine sorgente) invece dei limiti che hai appena impostato.


0

È possibile utilizzare drawable di dimensioni diverse che vengono utilizzati con densità / dimensioni dello schermo diverse, ecc. In modo che l'immagine appaia corretta su tutti i dispositivi.

Vedi qui: http://developer.android.com/guide/practices/screens_support.html#support


Uso la stessa immagine in luoghi diversi. Questo è il motivo per cui non posso ridimensionarlo, dovrebbe essere visualizzato nella dimensione che desidero.
Reto

0

Hai provato a avvolgere la tua immagine in uno ScaleDrawable e quindi a usarla nel tuo pulsante?


2
Ho appena provato questo, tuttavia il mio ScaleDrawable non viene visualizzato. :-( Anche non in ImageView. Ho preso il codice di esempio e ho appena sostituito il drawable. Qualche idea sul perché non funziona?
Reto

Ho avuto lo stesso problema. ScaleDrawablesarebbe perfetto, ma semplicemente non funziona. Sembra avere qualcosa a che fare con i "livelli". Maggiori informazioni qui (e alcune soluzioni che sono meno che perfetto): stackoverflow.com/questions/5507539/...
Zeh

(modifica) risolto con del codice generico! Soluzione qui che si permette ancora di uso ScaleDrawables: stackoverflow.com/a/13706836/439026
Zeh

0

Ecco la funzione che ho creato per ridimensionare i disegnabili vettoriali. L'ho usato per impostare il drawable composto TextView.

/**
 * 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;
}


0

È perché non l'hai fatto setLevel. dopo di te setLevel(1), verrà visualizzato come desideri


0

Utilizzo dell'estensione 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)

Suggerisco di creare una funzione di estensione su TextView ( Button la estende ) per un facile riutilizzo.

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)
}

La domanda riguardava Button, non TextView.
Firzen

1
Avresti dovuto leggere la risposta. Un pulsante estende TextView, quindi puoi usarlo per entrambi. Oppure modificare l'estensione per estendere solo un Button
Gibolt

-1

Ho provato le tecniche di questo post ma nessuna di esse è stata così attraente. La mia soluzione era quella di utilizzare una visualizzazione immagine e una visualizzazione testo e allineare la visualizzazione immagine in alto e in basso alla visualizzazione testo. In questo modo ho ottenuto il risultato desiderato. Ecco un po 'di codice:

<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>

-1

Ho creato una classe di pulsanti personalizzata per ottenere questo risultato.

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>

Utilizzo in 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>

1
Perché crei un Canvasin getResizedDrawablee lo attiri se non hai intenzione di farci niente? L'intera funzione potrebbe essere ridotta solo a drawable.setBounds(0, 0, mWidth, mHeight).
Antimonit
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.