fkm blog

software開発に関することを書いていきます

AppCompat-v7-21.0.2でpaddingが無視される話

5.0未満のデバイスMaterial Design対応するのに必須となるAppCompat-v7だが, v21.0.2の時点でEditTextなどのpaddingが無視されるバグが報告されてる.

Issue 77982 appcompat-v7 can't set padding on EditText or Spinner via xml

発生条件は次の通り.

  • AppCompat-v7を使っている(=ActionBarActivityをベースにしている)
  • レイアウトXMLで, EditTextにandroid:paddingLeftなどを指定している
  • それを, Android 5.0未満(KitKatなど)で動かす

5.0で動かすとちゃんとpaddingは適用さる.

Fragmentの場合はonViewCreated()で無理矢理paddingを設定することで, 一応回避はできる.

@InjectView(R.id.edit_email)
EditText mEmailEdit;

@InjectView(R.id.edit_password)
EditText mPasswordEdit;

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    float density = getResources().getDisplayMetrics().density;
    int paddingH = (int) (16 * density);
    // set paddingLeft & Right to EditText
    mEmailEdit.setPadding(paddingH, mEmailEdit.getPaddingTop(), paddingH, mEmailEdit.getPaddingBottom());
    mPasswordEdit.setPadding(paddingH, mPasswordEdit.getPaddingTop(), paddingH, mPasswordEdit.getPaddingBottom());
}

paddingTopやBottomは元々セットされていた値を使わないとレイアウトが崩れるので注意

2014-11-20追記

上記Issueのコメントに書きましたが, これ, 直らないです.

なぜpaddingが無視される?

1. Viewのルールとして, android:backgroundに9-patchが指定された場合, android:paddingで設定された値ではなく, 9-patchに指定されたpaddingが優先的に使用される
2. EditTextは, inflate時にTintEditTextに差し替えられる.
3. TintEditTextのコンストラクタで, こんなことやってる.

public TintEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs, TINT_ATTRS,
                defStyleAttr, 0);
        setBackgroundDrawable(a.getDrawable(0));
        a.recycle();
}

4. AppCompat-v7のテーマは, EditTextの背景を9-patchにしている.

<item name="editTextBackground">@drawable/abc_edit_text_material</item>

<!-- abc_edit_text_materialの中身 -->
<selector>
        <item android:state_enabled="true" android:state_focused="true" android:drawable="@drawable/abc_textfield_activated_mtrl_alpha"/>
        <item android:state_enabled="true" android:state_activated="true" android:drawable="@drawable/abc_textfield_activated_mtrl_alpha"/>
        <item android:state_enabled="true" android:drawable="@drawable/abc_textfield_default_mtrl_alpha"/>
        <item android:drawable="@drawable/abc_textfield_default_mtrl_alpha"/>
    </selector>