Referencing sibling layouts in Android Relative Layout (xml preview) - android

I'm confused about why we need the + in some sibling references but not others to make views render correctly in the android studio preview pane. (The behaviour when viewing in a running app differs, so is not in scope)
From the android guide docs under the ID section: The plus-symbol (+) means that this is a new resource name that must be created and added to our resources (in the R.java file).
From the Relative Layout Params docs android:layout_toLeftOf
Positions the right edge of this view to the left of the given anchor view ID. May be a reference to another resource, in the form "#[+][package:]type/name"
From Relative Layout Examples :
In your XML layout, dependencies against other views in the layout can be declared in any order. For example, you can declare that "view1" be positioned below "view2" even if "view2" is the last view declared in the hierarchy. The example below demonstrates such a scenario.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="16dp"
android:paddingRight="16dp" >
<EditText
android:id="#+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/reminder" />
<Spinner
android:id="#+id/dates"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_below="#id/name" <- no + as 'name' already declared?
android:layout_alignParentLeft="true"
android:layout_toLeftOf="#+id/times" /> <- + present as times not declared yet?
<Spinner
android:id="#id/times"
android:layout_width="96dp"
android:layout_height="wrap_content"
android:layout_below="#id/name"
android:layout_alignParentRight="true" />
<Button
android:layout_width="96dp"
android:layout_height="wrap_content"
android:layout_below="#id/times"
android:layout_alignParentRight="true"
android:text="#string/done" />
</RelativeLayout>
All this info leads me to believe that the + symbol is only used when referencing siblings, if the sibling is declared after the reference?
However this doesn't appear to be the case in my project:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/bg_grey_light"
android:paddingBottom="10dp">
<ImageView
android:id="#+id/img"
android:layout_width="match_parent"
android:layout_height="220dp"
android:adjustViewBounds="true" />
<TextView
android:id="#+id/some_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/img" <- This needs a + to render correctly..
android:text="#{some.name}"/>
</RelativeLayout>
So what is the rule for the + symbol, and is there any solid documentation that i've missed?

From the docs:
The at-symbol (#) at the beginning of the string indicates that the
XML parser should parse and expand the rest of the ID string and
identify it as an ID resource. The plus-symbol (+) means that this is
a new resource name that must be created and added to our resources
(in the R.java file). There are a number of other ID resources that
are offered by the Android framework. When referencing an Android
resource ID, you do not need the plus-symbol, but must add the android
package namespace, like so:
android:id="#android:id/empty"
Defining IDs for view objects is important when creating a
RelativeLayout. In a relative layout, sibling views can define their
layout relative to another sibling view, which is referenced by the
unique ID.
An ID need not be unique throughout the entire tree, but it should be
unique within the part of the tree you are searching (which may often
be the entire tree, so it's best to be completely unique when
possible).
Hope it will help you.
<- This needs a + to render correctly..
In preview mode, in your case it should render without without a +.
Try adding the tools namespace in the root layout as:
xmlns:tools="http://schemas.android.com/tools"
and then in your TextView:
tools:text="Some name"

Related

Why declaring #+id is allowed in other than id attributes

So lastly I have had to rebuild not my XML layout file for android app. And I saw constructions like
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/rev_main"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/rev_arrow">
<!-- some stuff in here -->
</LinearLayout>
<ImageView
android:id="#+id/rev_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/arrow"
/>
</RelativeLayout>
It is really annoying when I see that someone using #+id in not android:id attribute. When any developer will want to search this id he will find LinearLayout first instead ImageView.
My question is why google allow it? Is there any particular reason for it and I just didn't know it?
Sorry for my poor English.
Yes, there is a reason:
Sometimes, you have to set a View A relative to the position of a View B which is declared later in the XML-file (which is the case in your example. The LinearLayout is "View A" and the ImageView is "View B").
Imagine, the code you've got a problem with
android:layout_below="#+id/rev_arrow"
would look like this instead:
android:layout_above="#+id/rev_arrow"
The android:layout_above would be useless if you couldn't declare an id inside it.
Because it was mentioned in a few comments:
You have to use the "plus"-sign always at that place, where the id is first declared in the layout-file (from top to bottom). It is independet from the attribute, like "id" or "layout_below".
This is a valid use of the ID, as it tells the layout manager that the view identified by id/rev_main view is to be placed below the view identified by id/rev_arrow.
So in places other than android:id, the ids are used as references to views identified by the respective id.

toLeftOf resource not found

I've used toLeftOf many times before but it suddenly stopped working. I tried:
android:layout_toLeftOf="#id/spacer"
Here is the view:
<View
android:id="#+id/spacer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginLeft="#dimen/center_margin"
android:layout_marginStart="#dimen/center_margin"
android:layout_marginRight="#dimen/center_margin"
android:layout_marginEnd="#dimen/center_margin" />
And it gave me the errors:
Error:(16, 34) No resource found that matches the given name (at 'layout_toLeftOf' with value '#id/spacer').
Error:(17, 35) No resource found that matches the given name (at 'layout_toStartOf' with value '#id/spacer').
It works at other points in the app but for some reason it doesn't work here. Anyone know whats wrong?
Edit - Yes it is in a RelativeLayout. Here is a condensed version:
<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"
android:screenOrientation="portrait"
android:fitsSystemWindows="true"
android:focusableInTouchMode="true" >
<TextView
android:id="#+id/txt1" />
<View
android:id="#+id/spacer" />
<TextView
android:id="#+id/txt2" />
</RelativeLayout>
Upon further review I figured out the issue is I was trying to reference the View before it was made. I fixed this by changing #id/spacer to #+id/spacer
A bit late, but maybe still helpful for others. Took me 1 hour to find out my issue.
Non working example:
<TextView
android:id="#+id/firstview"
android:layout_toRightOf="#id/secondview"/>
<TextView
android:id="#+id/secondview"/>
Working example
<TextView
android:id="#+id/firstview"
android:layout_toRightOf="#+id/secondview"/>
<TextView
android:id="#+id/secondview"/>
Not the sign "+" being the only difference.
If you reference a view which is defined after the view you put the reference in, you need to use a +
Write the layout which is used as refrence, then the layout you want to put relative to that layout...
It's like trying to use variable before it was declared in the same class file.
You cannot reference a property that is not found in your respective ViewGroup. In this case you are trying to access properties that are specific to RelativeLayout. You cannot access these kinds of properties UNLESS your encapsulating view is in fact a RelativeLayout.
Note that this applies to the Parent layout that the view is encapsulated in.

RelativeLayout id references

These two views are inside of RelativeLayout. The IDE throws an error there is no #id/et_pass, but if I set #+id/et_pass it is OK. Why is that?
<ImageView
android:id="#+id/devider_zero"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#id/et_pass" <!-- Error is here -->
android:src="#drawable/registration_line" />
<EditText
android:id="#+id/et_pass"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/devider_first"
android:background="#android:color/transparent"
android:layout_gravity="left"
android:ellipsize="start"
android:ems="8"
android:hint="#string/password"
android:inputType="textPassword"
android:layout_marginTop="#dimen/register_layout_edittext_margin_top"
android:maxLines="1" />
The difference between #+id/something and #id/something is that the first one is creating an id, and the second one is referencing an id that has already been created. The first time that you mention an id you have to create it using #+id/, and anything after that can use #id/.
When you give a view the attribute android:id you do not have to use #+id/ if you have already used that somewhere earlier in your file.
Because of the way android compiles XML files, it reads your image view first, reaches the point where you write #id/ searches for an id in the R file, and can't find it. But if you call #+id/ the eclipse searches for the id in the R file, can't find it, and adds it.
Also, this is not specific to RelativeLayouts, if you put the same code in a linear layout, you would also get that error
#+id instructs the parser to create the ID if it does not exist. #id is used to refer to an existing ID.

Modifying nested attributes on an included Layout

I've been learning about merge and include lately, and I have a question I can't seem to figure out the answer too. Say I have a layout that defines a header component that I want to add to multiple layouts. However, I want to change the title, or icon of each header per each include usage. For example say I have the following layout:
<RelativeLayout android:layout_width="fill_parent"
android:layout_height="wrap_content"
style="#style/menu_header">
<Button android:id="#+id/backButton"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="#style/button"
android:text="#string/back"/>
<TextView style="#style/headerTitle"
android:layout_centerInParent="true"
android:text="${title}"
android:layout_height="wrap_content"
android:layout_width="wrap_content"/>
</RelativeLayout>
Then I can include that in other layouts using:
<LinearLayout ...>
<include android:id="#+id/searchHeader" layout="#layout/shared_header" title="Search"/>
...
</LinearLayout>
I know I can modify any layout_* attribute of the root element, but can I define other attributes that get substituted into the layout, like say "title" in this example, without having to create my own subclass of View, add declare-styleable definitions in valaues/resources, etc?
Having something like this would make creating reusable views so much simpler, but I can't seem to find any evidence that says if merge + include can do it.
The answer is nope. Unfortunately, Android isn't that powerful. You have to create your own extension of ViewGroup and write more code.

what is the difference betwenn #id/ and #+id/ in android? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
What is different between #+id/android:list and #id/android:list ??
What is the difference between #id/.. and #+id/..? I am not referring to the difference between
#android:id/.. and #id/..
Code Example:
<Button
android:id ="#id/add_button"
/>
<Button
android:id ="#+id/remove_button"
/>
What is the difference between the two id definitions above?
You must use the #+ notation on the first occurrence of the ID within an XML file. The second and subsequent times you can -- and should -- drop off the + sign. This will help catch typos.
For example, suppose that you have a RelativeLayout. You have a TextView in that RelativeLayout whose android:id is #+id/label. Later on in the layout XML file, you want to refer to that TextView from another one for positioning purposes (e.g., for android:layout_below).
If you typed in android:layout_below="#+id/labbel" (note the typo), at compile time, this will be considered OK. However, at runtime, things will not work, ranging from the widget being positioned incorrectly to an outright crash, depending on Android version.
If you typed in android:layout_below="#id/labbel" (note the typo and the missing + sign), then you would get a compile error.
UPDATE
Since I wasn't clear enough the first time, apparently, let's try again.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:id="#+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="URL:"
android:layout_alignBaseline="#+id/entry"
android:layout_alignParentLeft="true"/>
<EditText
android:id="#id/entry"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/label"
android:layout_alignParentTop="true"/>
<Button
android:id="#+id/ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/entry"
android:layout_alignRight="#id/entry"
android:text="OK" />
<Button
android:id="#+id/cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="#id/ok"
android:layout_alignTop="#id/ok"
android:text="Cancel" />
</RelativeLayout>
Above, you will see a RelativeLayout. You will notice that the first occurrences of each ID get the + sign. The second and subsequent occurrences of each ID do not get the + sign.
You could use the + sign on all of them, but then if you make a typo, the compiler will not catch the problem.
The + sign effectively states "allocate a new ID". Not having the + sign states "use a previously-allocated ID, or fail at compile time if there is no such ID".
In the Android layout resource XML source files :
"#+id/anyId" : to add new id
"#id/anyId" : to refer existing id
You should use "#id/anyId" only when "anyId" is already added to R.java class using "#+id/anyId"
From Android Guide
For the ID value, you should usually
use this syntax form: "#+id/name". The
plus symbol, +, indicates that this is
a new resource ID and the aapt tool
will create a new resource integer in
the R.java class, if it doesn't
already exist.
So + is for assigning a new id, it will also work when using existed id but it is not necessary there.
The second one:
<Button android:id ="#+id/remove_button" />
defines a new id. You would use the first one, when you want to reference the layout element. For example, in a relative layout:
android:layout_below="#id/remove_button"

Categories

Resources