Soru DrawableLeft düğmesinin metinle hizalanması


İşte benim düzenim:

enter image description here

Karşılaştığım konu çizilebilir onay işareti ile. Her ikisini de düğmenin içinde ortalanmış olan metnin yanında nasıl hizalayacağım? İşte XML:

<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=".PostAssignmentActivity" >

    <LinearLayout
        style="?android:attr/buttonBarStyle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal" >

        <Button
            style="?android:attr/buttonBarButtonStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:drawableLeft="@drawable/ic_checkmark_holo_light"
            android:text="Post" />

        <Button
            style="?android:attr/buttonBarButtonStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Cancel" />
    </LinearLayout>

</RelativeLayout>

Android: gravity = "center_vertical" uygulaması, metni çeker ve birlikte çekilebilir, ancak metin artık ortada hizalanmaz.


44
2018-02-03 00:36


Menşei




Cevaplar:


Çözüm 1

Set android:paddingLeft ilk düğmenizin içinde. Bu zorlayacak drawableLeft tarafından paddingLeft sağa miktar. Bu hızlı / hacky çözümü.

Çözüm 2

Bir ButtonView kullanmak yerine, hem bir metin görünümü hem de resim görüntüleme içeren bir LinearLayout kullanın. Bu bir daha iyi çözüm. Onay işaretinin konumlandırılmasında size daha fazla esneklik sağlar.

ButtonView'inizi aşağıdaki kodla değiştirin. İhtiyacın var LinearLayout ve TextView kullanmak buttonBarButtonStyle böylece arka plan renkleri seçim üzerinde doğru ve metin boyutu doğru. Ayarlaman gerek android:background="#0000" Çocuklar için, sadece LinearLayout arka plan rengini değiştirir.

<LinearLayout
    style="?android:attr/buttonBarButtonStyle"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:orientation="horizontal" >
    <ImageView 
        style="?android:attr/buttonBarButtonStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:clickable="false"
        android:background="#0000"
        android:src="@drawable/ic_checkmark_holo_light"/>
    <TextView
        style="?android:attr/buttonBarButtonStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" 
        android:clickable="false"
        android:background="#0000"
        android:text="Done" />
</LinearLayout>

Bunu denerken aldığım bazı ekran görüntüleri.

enter image description here enter image description here enter image description here


60
2018-02-03 01:15



Yuvalanmış LinearLayouts ile derin görünüm hiyerarşileri olması, ListViews içindeki performans nedenleriyle ilgili kötü bir fikirdir. Burada bir endişe olması gerektiğini düşünmüyorum. - Brian Attwell
Bu ayrıntılı bir yazma için teşekkürler! :) - Randall Ma
Bu performans ve kod okunabilirlik nedenleri için kötü bir çözümdür. Paddings kullanmak gitmek için daha iyi bir çözümdür ve eğer yeterli değilse, Button görünümünü ve çizim simgesini Canvas ve onDraw () yöntemiyle genişletmeyi düşünebilirsiniz. - pawelo
Pawla, iyi bir nokta tekrar ediyorsun. Düzeniniz çok sayıda düğme içeriyorsa (belki de bir ListView içinde), Çözüm # 1im tasarımınızı ele almıyor ve performans sorunları yaşıyorsanız: Hiyerarşinizdeki Görünüm sayısını en aza indirmek için Düğmeyi geçersiz kılmak isteyebilirsiniz. Ancak bunu RTL düzeninde test etmeyi unutmayın. - Brian Attwell
Yerçekimini merkezileştirmeyi unutmadınız mı? LinearLayout? - corsair992


Bu çözümlerden hiçbiri kabul edilemez satış dışı teklifler sunmadan doğru bir şekilde işe yaramadı (görünümleri olan bir düzen yaratın? İyi bir fikir değil). Öyleyse neden kendi kendine yuvarlanmıyorsun? Sahip olduğum şey bu:

enter image description here

İlk önce bir attrs.xml Bununla:

<resources>
    <declare-styleable name="IconButton">
        <attr name="iconSrc" format="reference" />
        <attr name="iconSize" format="dimension" />
        <attr name="iconPadding" format="dimension" />
    </declare-styleable>
</resources>

Bu, yeni görünümümüzde belirli boyutta bir metin, metinden dolgu ve resim oluşturmaya olanak tanır. Görünüm kodu şöyle görünüyor:

public class IconButton extends Button {
    private Bitmap mIcon;
    private Paint mPaint;
    private Rect mSrcRect;
    private int mIconPadding;
    private int mIconSize;

    public IconButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context, attrs);
    }

    public IconButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public IconButton(Context context) {
        super(context);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        int shift = (mIconSize + mIconPadding) / 2;

        canvas.save();
        canvas.translate(shift, 0);

        super.onDraw(canvas);

        if (mIcon != null) {
            float textWidth = getPaint().measureText((String)getText());
            int left = (int)((getWidth() / 2f) - (textWidth / 2f) - mIconSize - mIconPadding);
            int top = getHeight()/2 - mIconSize/2;

            Rect destRect = new Rect(left, top, left + mIconSize, top + mIconSize);
            canvas.drawBitmap(mIcon, mSrcRect, destRect, mPaint);
        }

        canvas.restore();
    }

    private void init(Context context, AttributeSet attrs) {
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.IconButton);

        for (int i = 0; i < array.getIndexCount(); ++i) {
            int attr = array.getIndex(i);
            switch (attr) {
                case R.styleable.IconButton_iconSrc:
                    mIcon = drawableToBitmap(array.getDrawable(attr));
                    break;
                case R.styleable.IconButton_iconPadding:
                    mIconPadding = array.getDimensionPixelSize(attr, 0);
                    break;
                case R.styleable.IconButton_iconSize:
                    mIconSize = array.getDimensionPixelSize(attr, 0);
                    break;
                default:
                    break;
            }
        }

        array.recycle();

        //If we didn't supply an icon in the XML
        if(mIcon != null){
            mPaint = new Paint();
            mSrcRect = new Rect(0, 0, mIcon.getWidth(), mIcon.getHeight());
        }
    }

    public static Bitmap drawableToBitmap (Drawable drawable) {
        if (drawable instanceof BitmapDrawable) {
            return ((BitmapDrawable)drawable).getBitmap();
        }

        Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);

        return bitmap;
    }
}

Ve sonra bu şekilde kullanılabilir:

<com.example.grennis.myapplication.IconButton
    android:layout_width="200dp"
    android:layout_height="64dp"
    android:text="Delete"
    app:iconSrc="@android:drawable/ic_delete"
    app:iconSize="32dp"
    app:iconPadding="6dp" />

Bu benim için çalışıyor.


31
2018-03-23 22:01



Android 5 lollipop üzerinde measureText () kullanarak kendinize dikkat edin, TÜM CAPS düğme metnini çizecektir, ancak measureText (), xml olarak tanımlandığı gibi dizgeyi döndürecektir. Bunu düzeltmek için açık tüm büyük harfleri kullanın. - Greg Ennis
Bu benim için en iyi çözüm çünkü varsayılan efektler olan malzeme tasarım düğmelerinin çoğaltılması gerekmiyordu - SIr Codealot
Bir hata imo dışında büyük bir çözüm. Görüntü ve metin ortalanmamış. Ortalamak için canvas.restore (); super.onDraw (tuval) hemen arkasında; - Emanuel Moecklin


Burada, Resim ve Metin ile ortalanmış olandan daha geniş bir Düğüme sahip olmanın sonuçlarını elde etmek için, hiçbir şey yapmadan, temiz, kolay bir yol.

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:clickable="true"
    android:background="@drawable/button_background_selector">

    <Button
        android:layout_centerInParent="true"
        android:gravity="center"
        android:duplicateParentState="true"
        android:layout_width="wrap_content"
        android:text="New User"
        android:textSize="15sp"
        android:id="@android:id/button1"
        android:textColor="@android:color/white"
        android:drawablePadding="6dp"
        android:drawableLeft="@drawable/add_round_border_32x32"
        android:layout_height="64dp" />

</RelativeLayout>

enter image description here


14
2018-04-02 19:35



Bu, bu tür düğmeleri oluşturmak için en kolay çözümdür. - Ionut Negru
RelativeLayout kullanarak korkunç yol, bunu yapmayın. - Pedro Paulo Amorim
RelativeLayout içinde standart bir Checkbox yerleştirmek benim için harika çalıştı. Düğme görüntüsü önyargılı olarak bırakıldı, metin üst / ekran boyutunun boyutuna bağlı olarak değişken bir uzaktaydı ... bir RelativeLayout içinde yuvalama onay kutusunun boyutunu normalleştirdi (düğme ve metin iyi görünüyordu) ve ortalanmış olmak. - WM1
Bunun için dezavantajı bir düğmeye benzemeyen şeylerin çoğunun kesilemez olması. Düğmenizde / etc'de durum değişikliği varsa, garip görünecektir. - JohnnyLambada
Benim için bu en kullanışlı parçaydı: "android: drawablePadding =" 6dp "Teşekkür ederim. - Roga Men


İşte kodum ve mükemmel çalışıyor.

<Button
    android:id="@+id/button"
    android:layout_width="200dp"
    android:layout_height="50dp"
    android:layout_gravity="center"
    android:background="@drawable/green_btn_selector"
    android:gravity="left|center_vertical"
    android:paddingLeft="50dp"
    android:drawableLeft="@drawable/plus"
    android:drawablePadding="5dp"
    android:text="@string/create_iou"
    android:textColor="@color/white" />

7
2018-05-08 06:41



Bu sadece düğme ayarlanmış bir boyut olduğunda çalışır. - Clive Jefferies
Düğmeler erişilebilirlik nedenlerinden dolayı daha iyidir. Erişilebilirlik özelliklerini kullanan kullanıcılar, içinde bir ImageView ve TextView ile bir LinearLayout basmaları gerektiğini bilmiyorlar. - adamame
İçin +1 android:drawablePadding mükemmel çalışır @CliveJefferies boyutları için çalışır wrap content - vedant


Bizim durumumuzda, varsayılan Button sınıfını (çeşitli stilleri ve davranışları miras almak için) kullanmak istedik ve koddaki düğmeyi oluşturabilmemiz gerekiyordu. Ayrıca, bizim durumumuzda, metin, bir simge (sol çekilebilir) veya her ikisini de alabilirdik.

Amaç, düğme genişliği wrap_content'ten daha geniş olduğunda, simge ve / veya metni bir grup olarak ortalamaktı.

public class CenteredButton extends Button
{
    public CenteredButton(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);

        // We always want our icon and/or text grouped and centered.  We have to left align the text to
        // the (possible) left drawable in order to then be able to center them in our onDraw() below.
        //
        setGravity(Gravity.LEFT|Gravity.CENTER_VERTICAL);
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        // We want the icon and/or text grouped together and centered as a group.

        // We need to accommodate any existing padding
        //
        float buttonContentWidth = getWidth() - getPaddingLeft() - getPaddingRight();

        // In later versions of Android, an "all caps" transform is applied to buttons.  We need to get
        // the transformed text in order to measure it.
        //
        TransformationMethod method = getTransformationMethod();
        String buttonText = ((method != null) ? method.getTransformation(getText(), this) : getText()).toString();
        float textWidth = getPaint().measureText(buttonText);

        // Compute left drawable width, if any
        //
        Drawable[] drawables = getCompoundDrawables();
        Drawable drawableLeft = drawables[0];
        int drawableWidth = (drawableLeft != null) ? drawableLeft.getIntrinsicWidth() : 0;

        // We only count the drawable padding if there is both an icon and text
        //
        int drawablePadding = ((textWidth > 0) && (drawableLeft != null)) ? getCompoundDrawablePadding() : 0;

        // Adjust contents to center
        //
        float bodyWidth = textWidth + drawableWidth + drawablePadding;
        canvas.translate((buttonContentWidth - bodyWidth) / 2, 0);

        super.onDraw(canvas);
    }
}

6
2018-05-29 21:22



Bu çözümü beğendim çünkü çizilebilir renk tonumu doğru bir şekilde oluşturdu. Ancak, bu simge soldaki simgeyle ortalanmıştı, bu kod ise simge + metni ortalar. Çeviriyi, Greg'in IconButton örneğindeki değerlerle değiştirdim, böylece işe yaradı: int left = (int) ((getWidth () / 2f) - (textWidth / 2f) - drawableWidth - drawablePadding); canvas.translate (sol, 0); - Dandalf
Kod için teşekkürler. Compat kütüphanesini kullanarak Tint'e sahip olmak için uzattım AppCompatButton normal Düğme yerine - Alin


public class DrawableCenterTextView extends TextView {

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

    public DrawableCenterTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public DrawableCenterTextView(Context context) {
        super(context);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Drawable[] drawables = getCompoundDrawables();
        if (drawables != null) {
            Drawable drawableLeft = drawables[0];
            Drawable drawableRight = drawables[2];
            if (drawableLeft != null || drawableRight != null) {
                float textWidth = getPaint().measureText(getText().toString());
                int drawablePadding = getCompoundDrawablePadding();
                int drawableWidth = 0;
                if (drawableLeft != null)
                    drawableWidth = drawableLeft.getIntrinsicWidth();
                else if (drawableRight != null) {
                    drawableWidth = drawableRight.getIntrinsicWidth();
                }
                float bodyWidth = textWidth + drawableWidth + drawablePadding;
                canvas.translate((getWidth() - bodyWidth) / 2, 0);
            }
        }
        super.onDraw(canvas);
    }
}

3
2017-12-09 13:08





Ben başladım @ BobDickinson'un cevabıAncak, çok sayıda çizgi ile iyi başa çıkmadı. Yaklaşım iyidir, çünkü hala bir Button Bu yeniden kullanılabilir.

Düğmenin birden fazla satıra sahip olması durumunda da çalışacak uyarlanmış bir çözüm (Lütfen nedenini sorma.)

Sadece uzatmak Button ve aşağıdakileri kullanın onDraw, getLineRight() Her satırın gerçek uzunluğunu aramak için kullanılır.

@Override
protected void onDraw(Canvas canvas) {
    // We want the icon and/or text grouped together and centered as a group.
    // We need to accommodate any existing padding
    final float buttonContentWidth = getWidth() - getPaddingLeft() - getPaddingRight();

    float textWidth = 0f;
    final Layout layout = getLayout();
    if (layout != null) {
        for (int i = 0; i < layout.getLineCount(); i++) {
            textWidth = Math.max(textWidth, layout.getLineRight(i));
        }
    }

    // Compute left drawable width, if any
    Drawable[] drawables = getCompoundDrawables();
    Drawable drawableLeft = drawables[0];
    int drawableWidth = (drawableLeft != null) ? drawableLeft.getIntrinsicWidth() : 0;

    // We only count the drawable padding if there is both an icon and text
    int drawablePadding = ((textWidth > 0) && (drawableLeft != null)) ? getCompoundDrawablePadding() : 0;

    // Adjust contents to center
    float bodyWidth = textWidth + drawableWidth + drawablePadding;

    canvas.save();
    canvas.translate((buttonContentWidth - bodyWidth) / 2, 0);
    super.onDraw(canvas);
    canvas.restore();
}

1
2017-09-19 08:18