背景Drawableを設定するとき、パディングはどこに行きますか?


86

私のビューEditTextButtonビューにこの問題があり、テキストから離れた場所に配置するための適切なパディングがありますが、背景を変更するとsetBackgroundDrawablesetBackgroundResourceそのパディングは永久に失われます。


2
この問題は、Android 4.4 KitKat
Vladimir

2
4.4.3を搭載したNexus5では、この問題は引き続き発生します。
Bianca Daniciuc 2015

1
Lollipop(5.0)でのみ修正されたと思います
Aviv Ben Shabat 2016

私はと同じ問題を抱えていましたがTextView、以下の受け入れられた解決策もそのタイプのビューで機能しました。
stonz2 2016

TextViewAPI 28(Android 9)でも問題が発生しています。修正されていないようです。
Sdghasemi

回答:


97

私が見つけたのは、バックグラウンドリソースとして9パッチを追加すると、パディングがリセットされることでした。興味深いことに、カラーまたは9以外のパッチ画像を追加した場合、追加されませんでした。解決策は、背景が追加される前にパディング値を保存し、後で再度設定することでした。

private EditText value = (EditText) findViewById(R.id.value);

int pL = value.getPaddingLeft();
int pT = value.getPaddingTop();
int pR = value.getPaddingRight();
int pB = value.getPaddingBottom();

value.setBackgroundResource(R.drawable.bkg);
value.setPadding(pL, pT, pR, pB);

このアプローチを使用して問題が発生した場合は、setBackgroundResource()を呼び出す前に必ずgetPadding ...を呼び出してください。
Chris.Zou 2013

この方法では、描画可能なパディングが維持されないようです。
Thuy Trinh 2014

4
Googleがこのバグを解決したので、API 19(キットカット)の上でこれを行う必要がないことを言及したいと思います。
ywwynm 2015

@ywwynmはキットカット以上ですか?
HendraWD 2016年

OK、私はそれを自分で試しました
。API19(キットカット

14

要素を別のレイアウト(この場合はFrameLayout。)内にラップすることができました。これによりFrameLayout、含まれているパディングを破壊することなく、の背景を変更することができましたRelativeLayout

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:id="@+id/commentCell"
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:background="@drawable/comment_cell_bg_single" >

    <RelativeLayout android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                    android:padding="20dp" >

    <ImageView android:id="@+id/sourcePic"
               android:layout_height="75dp"
               android:layout_width="75dp"
               android:padding="5dp"
               android:background="@drawable/photoframe" 
     />
...

もう1つのオプションは、Drawable上記のように背景を設定した後、プログラムで設定することです。デバイスの解像度を補正するために、必ずピクセルを計算してください。


12

TextViewでこの問題が発生したため、TextViewをサブクラス化し、メソッドのOverrideメソッドを作成しましたTextView.setBackgroundResource(int resid)。このような:

@Override
public void setBackgroundResource(int resid) {
    int pl = getPaddingLeft();
    int pt = getPaddingTop();
    int pr = getPaddingRight();
    int pb = getPaddingBottom();

    super.setBackgroundResource(resid);

    this.setPadding(pl, pt, pr, pb);
}

このように、リソースを設定する前にアイテムのパディングを取得しますが、パディングを維持する以外は、メソッドの元の機能を実際に混乱させることはありません。


9

これを徹底的にテストしていませんが、この方法は役に立つかもしれません:

    /**
 * Sets the background for a view while preserving its current padding. If the background drawable
 * has its own padding, that padding will be added to the current padding.
 * 
 * @param view View to receive the new background.
 * @param backgroundDrawable Drawable to set as new background.
 */
public static void setBackgroundAndKeepPadding(View view, Drawable backgroundDrawable) {
    Rect drawablePadding = new Rect();
    backgroundDrawable.getPadding(drawablePadding);
    int top = view.getPaddingTop() + drawablePadding.top;
    int left = view.getPaddingLeft() + drawablePadding.left;
    int right = view.getPaddingRight() + drawablePadding.right;
    int bottom = view.getPaddingBottom() + drawablePadding.bottom;

    view.setBackgroundDrawable(backgroundDrawable);
    view.setPadding(left, top, right, bottom);
}

view.setBackgroundDrawable(Drawable)の代わりにこれを使用してください。


3
ビューの一部にすでにパディングがある場合、この関数を複数回呼び出した後、ビューのパディングを前の値でインクリメントするため、背景画像が横に移動します
iBog 2013

ええ、パディングが数回変更される場合は、別のアプローチを取りたいと思うでしょう。おそらく、元のパディングとドローアブルパディングを追跡します。
cottonBallPaws

2

CottonBallPawsの回答の後方互換バージョン

/** 
  * Sets the background for a view while preserving its current     padding. If the background drawable 
  * has its own padding, that padding will be added to the current padding. 
 *  
 * @param view View to receive the new background. 
 * @param backgroundDrawable Drawable to set as new background. 
 */ 
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@SuppressWarnings("deprecation")
public static void setBackgroundAndKeepPadding(View view, Drawable backgroundDrawable) {
    Rect drawablePadding = new Rect();
    backgroundDrawable.getPadding(drawablePadding);
    int top = view.getPaddingTop() + drawablePadding.top;
    int left = view.getPaddingLeft() + drawablePadding.left;
    int right = view.getPaddingRight() + drawablePadding.right;
    int bottom = view.getPaddingBottom() + drawablePadding.bottom;

    int sdk = android.os.Build.VERSION.SDK_INT;
    if(sdk < android.os.Build.VERSION_CODES.JELLY_BEAN) {
        view.setBackgroundDrawable(backgroundDrawable);
    } else {
        view.setBackground(backgroundDrawable);
    }
    view.setPadding(left, top, right, bottom);
}

1

9パッチの画像を使用し、ドローアブルのコンテンツ領域を定義することで、パディングを行うことができます。 これをチェックして

xmlから、またはプログラムでレイアウトのパディングを設定することもできます

xmlパディングタグ

android:padding
android:paddingLeft
android:paddingRight
android:paddingTop
android:paddingBottom

EditTextまたはボタンビューでsetPaddingを呼び出して、setBackgroundDrawableを呼び出した後、コードから手動でパディングを設定してみることができます。


XMLでEditTextとButtonにパディングを定義しましたが、Drawableを変更するまで、パディングが失われます。
Dandre Allison 2012

以前のドローアブルと新しいドローアブルの間のコンテンツ領域の変更に応じて変更される場合があります。パディングを増やしてみて、パディングが行われているかどうかを確認しましたか。
achie 2012

1
申し訳ありませんが、あなたの質問を完全に読むべきでした。backgrounddrawableを変更しているため、パディングが削除されている可能性があります。それが事実かどうかはわかりません。ただし、その場合は、EditTextまたはボタンビューでsetPaddingを呼び出してsetBackgroundDrawableを呼び出した後、コードから手動でパディングを設定してみることができます
achie 2012

1

一般的な検索者の場合、

setBackgroudDrawableの後にsetPaddingを追加するだけです。ドローアブルを変更するときは、setPaddingを再度呼び出す必要があります。

お気に入り:

view.setBackgroundDrawable(backgroundDrawable);
view.setPadding(x, x, x, x);

最もクリーンな方法は、drawable-image-fileを指すxml-drawable内にパディングを定義することです。

Greatings


1

私の解決策は、ビュー(私の場合はEditText)とオーバーライドsetBackgroundDrawable()setBackgroundResource()メソッドを拡張することでした

// Stores padding to avoid padding removed on background change issue
public void storePadding(){
    mPaddingLeft = getPaddingLeft();
    mPaddingBottom = getPaddingTop();
    mPaddingRight = getPaddingRight();
    mPaddingTop = getPaddingBottom();
}

// Restores padding to avoid padding removed on background change issue
private void restorePadding() {
    this.setPadding(mPaddingLeft, mPaddingTop, mPaddingRight, mPaddingBottom);
}

@Override
public void setBackgroundResource(@DrawableRes int resId) {
    storePadding();
    super.setBackgroundResource(resId);
    restorePadding();
}

@Override
public void setBackgroundDrawable(Drawable background) {
    storePadding();
    super.setBackgroundDrawable(background);
    restorePadding();
}

1

すべてのソリューションを組み合わせて、Kotlinで次のように作成しました。

fun View.setViewBackgroundWithoutResettingPadding(@DrawableRes backgroundResId: Int) {
    val paddingBottom = this.paddingBottom
    val paddingStart = ViewCompat.getPaddingStart(this)
    val paddingEnd = ViewCompat.getPaddingEnd(this)
    val paddingTop = this.paddingTop
    setBackgroundResource(backgroundResId)
    ViewCompat.setPaddingRelative(this, paddingStart, paddingTop, paddingEnd, paddingBottom)
}

fun View.setViewBackgroundWithoutResettingPadding(background: Drawable?) {
    val paddingBottom = this.paddingBottom
    val paddingStart = ViewCompat.getPaddingStart(this)
    val paddingEnd = ViewCompat.getPaddingEnd(this)
    val paddingTop = this.paddingTop
    ViewCompat.setBackground(this, background)
    ViewCompat.setPaddingRelative(this, paddingStart, paddingTop, paddingEnd, paddingBottom)
}

1

何が起こっているのかを説明するだけです:

それは実際には機能です。背景として使用する可能性のあるレイアウトドローアブルは、次のようにパディングを定義できます。

<layer-list
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:paddingRight="8dp"
    >
    ...
</layer-list>

このパディングは、新しい描画可能な背景とともに設定されます。パディングがない場合、デフォルト値は0です。

Romain Guyが書いたメールの詳細:https//www.mail-archive.com/android-developers@googlegroups.com/msg09595.html


0

このコンパイルのようにAndroidStudioでlibをv7:22.1.0に変更するだけです 'com.android.support:appcompat-v7:22.1.0'


0

ほとんどの回答は正しいですが、バックグラウンド設定を正しく処理する必要があります。

最初にビューのパディングを取得します

//Here my view has the same padding in all directions so I need to get just 1 padding
int padding = myView.getPaddingTop();

次に、背景を設定します

//If your are supporting lower OS versions make sure to verify the version
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) {
    //getDrawable was deprecated so use ContextCompat                            
    myView.setBackgroundDrawable(ContextCompat.getDrawable(context, R.drawable.bg_accent_underlined_white));
} else {
    myView.setBackground(ContextCompat.getDrawable(context, R.drawable.bg_accent_underlined_white));
}

次に、背景が変更される前にビューにあったパディングを設定します

myView.setPadding(padding, padding, padding, padding);

0

私は別の解決策を見つけました。私はボタンで同様の問題に直面していました。最終的に、私は追加しました:

android:scaleX= "0.85"
android:scaleY= "0.85"

それは私のために働いた。デフォルトのパディングはほとんど同じです。


0

私の場合、ドローアブルがあり、非常に愚かだったので、xmlでパディングがすべて0に設定されているのがわかりませんでした。


-1

ここでは、cottonBallPawsのsetBackgroundAndKeepPaddingの改良版を紹介します。これにより、メソッドを複数回呼び出した場合でもパディングが維持されます。

/**
 * Sets the background for a view while preserving its current padding. If the background drawable
 * has its own padding, that padding will be added to the current padding.
 */
public static void setBackgroundAndKeepPadding(View view, Drawable backgroundDrawable) {

    Rect drawablePadding = new Rect();
    backgroundDrawable.getPadding(drawablePadding);

    // Add background padding to view padding and subtract any previous background padding
    Rect prevBackgroundPadding = (Rect) view.getTag(R.id.prev_background_padding);
    int left = view.getPaddingLeft() + drawablePadding.left -
            (prevBackgroundPadding == null ? 0 : prevBackgroundPadding.left);
    int top = view.getPaddingTop() + drawablePadding.top -
            (prevBackgroundPadding == null ? 0 : prevBackgroundPadding.top);
    int right = view.getPaddingRight() + drawablePadding.right -
            (prevBackgroundPadding == null ? 0 : prevBackgroundPadding.right);
    int bottom = view.getPaddingBottom() + drawablePadding.bottom -
            (prevBackgroundPadding == null ? 0 : prevBackgroundPadding.bottom);
    view.setTag(R.id.prev_background_padding, drawablePadding);

    view.setBackgroundDrawable(backgroundDrawable);
    view.setPadding(left, top, right, bottom);
}

values /ids.xmlを介してリソースIDを定義する必要があります。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="prev_background_padding" type="id"/>
</resources>

-1

私はこの非常に簡単な回避策を使用しますaccentColorstyle.xmlは以下のように私のように定義します

<item name="colorAccent">#0288D1</item>

次に、Buttonタグで次のいずれかのスタイルを使用します

style="@style/Base.Widget.AppCompat.Button.Colored"
style="@style/Base.Widget.AppCompat.Button.Small"

例えば ​​:

<Button
    android:id="@+id/btnLink"
    style="@style/Base.Widget.AppCompat.Button.Colored"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@id/tvDescription"
    android:textColor="@color/textColorPrimary"
    android:text="Visit Website" />

<Button
    android:id="@+id/btnSave"
    style="@style/Base.Widget.AppCompat.Button.Small"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@id/tvDescription"
    android:layout_toRightOf="@id/btnLink"
    android:textColor="@color/textColorPrimaryInverse"
    android:text="Save" />

これは質問とは関係ありません。
miha_x64 2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.