Global or local id for views inside a layout? - android

When assigning an id to a view of a layout in an xml resource, I usually do something like this:
(example)
contact_info.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/contact_info_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Here the TextView contains the name of a contact.
Is it better to use a complete id like that or just "name" is enough?

Appropriate convention would be like this:
From the example you have provided, the appropriate id for the text view would be: contactinfo_textview_name
Please note that, its NOT rule. You can use anything you are comfortable with! cheers

As I indicated Hardik4560, it is best to names that are sufficiently descriptive and not too long.
Realize that your application can grow much (who knows!?) and there may come a time when no longer know to which each identifier belongs layout.
Regards!

Related

Android: Why subtitle in ListView not grey?

I use latest Android Studio and SDK. In preview & real device i see this:
My code:
<?xml version="1.0" encoding="utf-8"?>
<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"
tools:context="com.myappname.view.AboutActivity">
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/listViewAbout" />
</RelativeLayout>
How i make subtitle text color is gray? Like this:
I'm going out on a limb and assume that you're using the row layout simple_list_item_2.xml (based on the screenshot) which gives you two rows. The problem, if you may call it that, is that depending on the SDK version, the styling for this layout has changed.
On SDK 23, it looks like this:
However, on say SDK 19, it looks like this:
Why?
To understand this we first need to take a look at the xml that generates the rows from simple_list_item_2.xml, you'll see it's a pretty simple layout that uses the now deprecated view TwoLineListItem but that's just a plus on why to use your custom layout.
<TwoLineListItem xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/listPreferredItemHeight"
android:mode="twoLine"
android:paddingStart="?attr/listPreferredItemPaddingStart"
android:paddingEnd="?attr/listPreferredItemPaddingEnd">
<TextView android:id="#id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:textAppearance="?attr/textAppearanceListItem" />
<TextView android:id="#id/text2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/text1"
android:layout_alignStart="#id/text1"
android:textAppearance="?attr/textAppearanceListItemSecondary" />
</TwoLineListItem>
The reason is because of the way the style textAppearanceListItemSecondary is resolved in each SDK version. The style is what gives the text the size, the color, etc. The evolution of the interface in Android has given birth to a huge ecosystem of themes and relying on the default styling will result in inconsistencies like the one you stumbled upon.
What to do about it?
You should use your own layout for this to allow for uniform styling across versions. To do so, please refer to any of the multiple questions covering this matter. But in short it just means creating a layout file, call it for example custom_row.xml and having the layout look exactly as you please. This also gives you total control over placement of the items, extra Views that you may need, and overhead in terms of coding is minimal compared to the SimpleAdapter or ArrayAdapter that perhaps you were using.
Note
You should consider moving your code towards RecyclerView instead of ListView if you haven't already.
You can set Textview property
android:textColor="#color/grey"
in you Adapter layout to change colour of your sub item
Hope this will help

Android layout reference xml element later in file

How do I reference a later XML element?
Here's a specific use case. Let's say I have a form with a root LinearLayout, containing LinearLayouts for multiple rows, each row having one or more text input areas.
Here's a visual of what I'm going for. First pic is from Venmo's app, second is a rendering of the following XML.
Such a layout could look like this:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="#+id/row_card_number"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<EditText
android:id="#+id/card_number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nextFocusDown="#id/month"/>
</LinearLayout>
<LinearLayout
android:id="#+id/row_date"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<EditText
android:id="#+id/month"
android:layout_height="wrap_content"
android:layout_width="100dp"
android:nextFocusDown="#id/year"/>
<EditText
android:id="#+id/year"
android:layout_height="wrap_content"
android:layout_width="match_parent"/>
</LinearLayout>
</LinearLayout>
In this use case, forward referencing is necassary in order to set the next focus element. That way, when you press the next button on the keyboard, it'll go to the correct view. In this sample xml, without the nextFocusDowns, pressing next would go from name to month, and never go to year.
However, if you try to compile this, you'll get an error:
Error:(18, 36) No resource found that matches the given name (at 'nextFocusDown' with value '#id/month').
This is because the id month hasn't yet been initialized when I'm trying to reference it, since that's later in the file. How can I reference an id in xml that appears later in the file?
The simplest solution is just to replace
android:nextFocusDown="#id/month"
with
android:nextFocusDown="#+id/month"
When the compiler is parsing your XML to add the id's to R.java, it just reads top to bottom. When you have #id/month, it searches through the existing id's, and fails to find it.
However, if you do #+id/month, it creates a new id, and links to that. When it gets to android:id=#+id/month in the actual month view, it links it to the same id that we already created.
This brings up the question: If you can replace #id/ with #+id/, and #+id/ will work regardless of the order of elements, why even bother to use #id/?
The reason for this is if the id doesn't exist, #id/ will throw a compiler error, while #+id/ will log a warning at runtime.
Consider this XML:
<EditText
android:id="#+id/month"
android:layout_height="wrap_content"
android:layout_width="100dp"
android:nextFocusDown="#+id/SOME_RANDOM_ID"/>
<EditText
android:id="#+id/year"
android:layout_height="wrap_content"
android:layout_width="match_parent"/>
When this is parsed, a new id element SOME_RANDOM_ID is created. However, when Android tries to apply it at runtime, it can't find an element with that id. If you look at Logcat, you'll see this:
W/View﹕ couldn't find view with id 2131689604
This log message is both hard to find and hard to debug. One small typo in a #+id/ and you'll have a bug that could be incredibly difficult to debug. However, if we had done:
android:nextFocusDown="#id/SOME_RANDOM_ID"
Then we'd get a compiler error, something like:
Error:(18, 36) No resource found that matches the given name (at 'nextFocusDown' with value '#id/SOME_RANDOM_ID').
This is much easier to find and debug.
tl;dr: You can use #+id/ instead of #id/ and you'll be able to forward reference, but note that that can make small typos incredibly difficult to debug.
You might be able to use a RelativeLayout to make all the Views exist in reverse order in the xml, but that seems like overkill to me.
I had the same issue recently and I used #+id/my_new_id the first time I referenced the element and later in the XML in the element definition, I assigned #id/my_new_id to the android:id attribute. It seems it works fine and it's not necessary write #+id with the same id more than one time avoiding possible warnings.
For example:
<LinearLayout
...
android:layout_toLeftOf="#+id/my_new_id"
... >
...
</LinearLayout>
<ImageButton
android:id="#id/my_new_id"
... />

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.

Android nested layout

I am developing my first Android app. Although I have 15 years of Java software development experience, Android is new to me. My desired look is a background image with other images on top of it, as well as labels and phone numbers. It seems like the best way to accomplish this is a Linear Layout for the background image, with a nested layout for the other fields on top of that. I have searched online and cannot find any sample code on how to accomplish this. Any recommendations would be greatly appreciated. Thanks in advance.
What are you using to develop? If you are you using Eclipse with the Android SDK this is super easy. Put the desired picture in the appropriate drawable folder, go to the graphical view of layout that corresponds to your activity, on the right side of the screen there is a list of all the properties, find background, then select your picture from drawables. You can also do this from the xml using android:background="#drawable/yourPic". This way you don't have to worry about having things layered on top of it.
I think you should go through followings:
1. http://phandroid.com/2011/05/11/10-tips-for-android-ui-design/
2. http://mobile.tutsplus.com/series/android-user-interface-design/
3. http://coding.smashingmagazine.com/2011/06/30/designing-for-android/
4. http://android-developers.blogspot.in/2011/09/thinking-like-web-designer.html
If I got, something like this can work:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<stuff>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<stuff>
</RelativeLayout>
<stuff>
</RelativeLayout>
I used it in an app, and made the trick.
First of all, RelativeLayout is the best layout to use. It depends on your design.
If your design says to keep all the views either vertically OR horizontally, you can use LinearLayouts in between.
My suggested way:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout android:id="#+id/layout1"
android:layout_width="match_parent"
android:layout_height="wrap_parent"
android:orientation="Horizontal">
<View1 />
<View2 />
</LinearLayout>
</LinearLayout android:id="#+id/layout2"
android:layout_width="match_parent"
android:layout_height="wrap_parent"
android:orientation="Vertical"
android:layout_below="#id/layout1">
<View3 />
<View4 />
</LinearLayout>
</RelativeLayout>
Which will yield you something like this

Android: How to use an xml string value to determine layout orientation

I have a simple linear layout that I would like to change based on the screen size of the device. What I am trying to do is something like
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="#string/cover_orientation"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
I have created different dimen.xml files under values and values-xlarge so that the cover_orientation variable will take on a different value (either 'vertical' or 'horizontal') based on the screen size.
string name="cover_orientation">"vertical"
But this doesn't work. I have found a temporary work around that involves checking the screen size and changing the orientation manually:
if(getResources().getString(R.string.screen_size) == "xlarge"){
((LinearLayout)convertView).setOrientation(1);
}
but it seems like you should be able to do it the first way (much more elegant/less code).
I considered just having a different layout for each screen size, but the layout is actually quite big and this is the only change I need for the different screen sizes. So it didn't make much sense to me to duplicate the entire layout.
Thanks!
A nice way to do this is to add
android:orientation="#integer/cover_orientation"
on your LinearLayout and defining it like below.
in values/consts.xml:
<resources>
<integer name="orientation_horizontal">0</integer>
<integer name="orientation_vertical">1</integer>
</resources>
in values/something.xml:
<resources>
<integer name="cover_orientation">#integer/orientation_vertical</integer>
</resources>
in values-land/something.xml:
<resources>
<integer name="cover_orientation">#integer/orientation_horizontal</integer>
</resources>
This way you avoid hardcoding zeros and ones in your orientation variable definitions across the app.
I eventually found a solution to the problem by looking around the android docs. What I originally had was a LinearLayout, that contained an image an text inside of it (there was actually a lot more content inside of it but I'll keep it simple for this example), that looked something like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ImageView android:id="#+id/cover"
android:layout_width="#dimen/cover_width"
android:layout_height="#dimen/cover_height"/>
<TextView android:id="#+id/title"
android:gravity="top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:textSize="#dimen/title_font_size"
android:scrollHorizontally="true"
android:maxLines="1"
android:ellipsize="end" />
</LinearLayout>
What I wanted was to be able to dynamically change whether the text was beside the image or below the image, based on the device screen size. In other words i wanted to dynamically change the android:orientation dynamically. My first thought, which I posted in my question, was to have a string variable declared in the res/values/dimen.xml as
<string name="orientation">horizontal</string>
and another string variable declared in res/values-large/dimen.xml as
<string name="orientation">vertical</string>
Then when I was setting the orientation in the LinearLayout I thought I could use
android:orientation="#string/orientation"
But this didn't work. What I ended up doing was splitting the layout up. I originally had reservations about having two separate layouts because I thought I would have a lot of duplicated code for one simple change. That was before I learned about include and merge. First I created a common layout file that was the image and text in res/layout/content.xml that looked like:
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<ImageView android:id="#+id/cover"
android:layout_width="#dimen/cover_width"
android:layout_height="#dimen/cover_height"/>
<TextView android:id="#+id/title"
android:gravity="top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:textSize="#dimen/title_font_size"
android:scrollHorizontally="true"
android:maxLines="1"
android:ellipsize="end" />
</merge>
(Sidenote: I was originally confused at what the merge tag did. It is not merging what is inside the merge tag (in this example the image and the text) it is basically saying whatever parent file includes this file, merge the contents in between the tags into the parent file)
Then I created two separate files for just the LinearLayout that included the image and description xml file. One in res/layout/container.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/library_item_container"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<include layout="#layout/content"/>
</LinearLayout>
and one in res/layout-large/container.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/library_item_container"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<include layout="#layout/library_item_contents"/>
</LinearLayout>
Notice the only difference between the two container.xml files is that the orientation has changed from vertical to horizontal. Now there is minimal code that is repeated and problem is solved!
#odiggity, thank you for posting this question. I was trying the same. Application crashed upon starting.
I would assume that it's a runtime typing issue. In other words, there are only two legal values for the orientation attribute, which is not reflected by the string "type". What the framework would probably have to do is introduce another specialized resource type, similar to dimen or boolean.
I feel there is an answer to your question which addresses more cases than your own answer above. One can use style inheritance to define all attributes except orientation in an orientation-independent parent style and then add only the orientation in a small orientation-dependent style definition with that as a parent.
This way, one can avoid duplication even in complex cases.
I suggest you do some reading: http://developer.android.com/guide/practices/screens_support.html

Categories

Resources