LoginSignup
7
7

More than 5 years have passed since last update.

RelativeLayoutの位置調整でハマる

Last updated at Posted at 2015-05-21

何がしたかった?

ListViewの一部でレイアウトを変更したかった.
極端な例を挙げると,リストには文字列がひとつあり,通常はセンタリングされている.
これを,positionが偶数のリストアイテムだけ,文字列を左寄せにしたいという感じ.

コード例

既にテキストをセンタリング済みのリストアイテム用ViewXML

list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    android:id="@+id/rootLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:textSize="18sp" />

</RelativeLayout>

レイアウトファイルをInflateするAdapter

ItemAdapter.java

  @Override
  public View getView(final int position, final View convertView, final ViewGroup parent) {

    // ViewHolder使っての前処理を省略
    final ViewHolder holder = convertView.getTag();

    if(position % 2 == 0) {
       // positionが偶数ならテキストを左寄せ
       RelateiveLayout.LayoutParams params = (RelativeLayout.LayoutParams) holder.text.getLayoutParams();
       params.leftMargin = 10;
       params.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
       holder.text.setLayoutParams(params);
    } else {
       // positionが奇数ならテキストをセンタリングに戻す
       RelateiveLayout.LayoutParams params = (RelativeLayout.LayoutParams) holder.text.getLayoutParams();
       params.leftMargin = 0;
       params.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
       holder.text.setLayoutParams(params);
    }
    return convertView;
  }

結果

一見うまくいったように見えたのもつかの間.
めくるとpositionが奇数・偶数に関わらず,どんどん左寄せされて,センタリングされなかった.
どうやらListViewによるconvertViewが使い回され,ALIGH_PARENT_LEFTのルールが残り続けている.

問題点

LayoutParams.addRule の名のとおり,addRuleメソッドはルールを追加するものであり,上書きするものでは無かった.
そのため,positionが奇数時の処理において ALIGN_PANRET_LEFT のルールは残っており,その上でCENTER_HORIZONTALのルールが追加されただけだった.

解決

API Level 17の場合,RelativeLayout.LayoutParams.removeRule(int anchor) メソッドでルールを削除することができる.

example
params.removeRule(RelativeLayout.ALIGN_PARENT_LEFT);

API Level 17未満の場合は,以下の指定で削除を行う

example
params.addRule(RelativeLayout.ALIGN_PARENT_LEFT, 0);

addRuleを呼び出し,削除したいルールを第一引数に,削除するというアンカー0を第二引数に渡す.
元々指定用AnchorでRelativeLayout.TRUEという定数は用意されているが,FALSEは無い.
JavaDocを読むと,FALSEは0を指定しろと書いてあった.

        /**
         * Adds a layout rule to be interpreted by the RelativeLayout. Use this for
         * verbs that take a target, such as a sibling (ALIGN_RIGHT) or a boolean
         * value (VISIBLE).
         *
         * @param verb One of the verbs defined by
         *        {@link android.widget.RelativeLayout RelativeLayout}, such as
         *         ALIGN_WITH_PARENT_LEFT.
         * @param anchor The id of another view to use as an anchor,
         *        or a boolean value(represented as {@link RelativeLayout#TRUE})
         *        for true or 0 for false).  For verbs that don't refer to another sibling
         *        (for example, ALIGN_WITH_PARENT_BOTTOM) just use -1.
         * @see #addRule(int)
         */

基本的に一度inflateしたViewのLayoutParamsをいじることって無いので,なかなか抜け出せず,いやーハマったハマった…

7
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7