irobotxx
irobotxx

Reputation: 6063

issue with "@id" vs "@+id" in positioning in Relative Layout

Good day, i have a slight issue with relative layouts and i don't know why. Normally when you trying to position relative to other views, you use "@id" but it doesn't seem to position at all. only when i use the value "@+id" would it go correctly. in the example below, i have 4 views in a horizontal orientation i want the TextView with "percentage_id" to be positioned in between the imageviews but closer to the last one.

<RelativeLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >

    <TextView
        android:id="@+id/sales_id"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_marginLeft="10dp"
        android:text="£0.00"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:textColor="#AADDEE"
        android:textSize="18sp"
        android:textStyle="bold" >
    </TextView>

    <ImageView
        android:id="@+id/arrow_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_toRightOf="@id/sales_id"
        android:baselineAlignBottom="true"
        android:src="@drawable/rightarrow" >
    </ImageView>

    <TextView
        android:id="@+id/percentage_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toLeftOf="@id/imagearrow_id"
        android:layout_toRightOf="@id/arrow_id"
        android:text="0.00%"
        android:textColor="#606090"
        android:textSize="18sp" >
    </TextView>

    <ImageView
        android:id="@+id/imagearrow_id"
        android:layout_width="20dp"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_marginLeft="2dp"
        android:layout_weight="0"
        android:gravity="right"
        android:padding="5dp"
        android:src="@drawable/rightarrow" >
    </ImageView>

</RelativeLayout>

Now no matter what i do, it just goes to the default position in the relative layout and only when i use "@+id" instead of "@id" does it go to the correct position. I know sometimes it can give error if the view am trying to reference has not been declared yet but even if i place the textview last, i still can't get it where i want until i use "@+id".

is this is a new thing that works also with Relative Layout? because i have no idea why its not working with "@id". am i fine this way? anyone encountered the same issue? see some tutorials on the net use "@+id" for positioning too. Thank you

Upvotes: 19

Views: 5704

Answers (3)

Jamal S
Jamal S

Reputation: 1835

After experimenting with ConstraintLayout, check the snippet of code below, both views are wrapped in constraintLayout, i'll just paste the case code:

<android.support.v4.widget.ContentLoadingProgressBar
            android:id="@+id/progress"
            android:layout_width="150dp"
            android:layout_height="150dp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintVertical_bias="0.3"
            style="?android:attr/progressBarStyleLarge"
            android:visibility="@{safeUnbox(viewmodel.isLoading) ? View.VISIBLE : View.INVISIBLE}"
            />

        <TextView
            android:id="@+id/click_load"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:gravity="center_horizontal"
            android:text="@{viewmodel.text}"
            android:textSize="22sp"
            android:visibility="@{safeUnbox(viewmodel.isLoading) ? View.INVISIBLE : View.VISIBLE}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/progress"
            tools:text="ojoooihoihohoihiohhoihio" />

the line:

 app:layout_constraintTop_toBottomOf="@id/progress"

displays the textview pinned to the top of the view window in the editor, everything look fine in runtime but still this was confusing, now if you write it this way

 app:layout_constraintTop_toBottomOf="@+id/progress"

displays textview below the progress in UI editor as expected, reading through kcoppock explanation i find it matching the case.

Upvotes: 0

Kevin Coppock
Kevin Coppock

Reputation: 134684

Although you can refer to views declared later in the hierarchy, the XML document is still parsed sequentially. The first time that you refer to a particular ID, you have to prefix it with @+id. In actuality, you can prefix every reference to an ID with @+id and everything will work -- in fact, this is what happens if you design your interface with the graphical editor. Just to be safe, everything is prefixed with @+id. The + simply tells it to generate an ID in R.java if and only if it has not already been defined. If you try to define it more than once, it just sees that it's already been defined and continues on normally.

In your XML, you reference imagearrow_id from your percentage_id TextView. However, at this point the imagearrow_id has not yet been defined. For this scenario, you could simply prefix the layout_toLeftOf=@+id/imagearrow_id in your TextView, and then below, when defining your ImageView (imagearrow_id), you would not need the + in the android:id attribute.

Upvotes: 31

Raghav Sood
Raghav Sood

Reputation: 82563

@+id is used when declaring the ID for the first time, and you should not use it in the positioning of elements. It should be used only for the android:id attribute.

@id on the other hand is used to reference an existing ID.

In a RelativeLayout, you cannot reference views below the referencing view in the current code. So if you have the following layout:

LayoutRoot
    View1
    View2
    View3

View1 cannot, or rather should not, use View2 and View3 to define its position. View2 should use only View1 to define its position, and View3 can use both View1 and View2.

Essentially, you can use @id whenever the view you're referencing through it has been declared above the referencing view in the layout file.

So simply switching the code blocks' position of your last two widgets should allow you to use @id:

<RelativeLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >

    <TextView
        android:id="@+id/sales_id"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_marginLeft="10dp"
        android:text="£0.00"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:textColor="#AADDEE"
        android:textSize="18sp"
        android:textStyle="bold" >
    </TextView>

    <ImageView
        android:id="@+id/arrow_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_toRightOf="@id/sales_id"
        android:baselineAlignBottom="true"
        android:src="@drawable/rightarrow" >
    </ImageView>

    <ImageView
        android:id="@+id/imagearrow_id"
        android:layout_width="20dp"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_marginLeft="2dp"
        android:layout_weight="0"
        android:gravity="right"
        android:padding="5dp"
        android:src="@drawable/rightarrow" >
    </ImageView>

    <TextView
        android:id="@+id/percentage_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toLeftOf="@id/imagearrow_id"
        android:layout_toRightOf="@id/arrow_id"
        android:text="0.00%"
        android:textColor="#606090"
        android:textSize="18sp" >
    </TextView>

</RelativeLayout>

Upvotes: 3

Related Questions