Using a non-android namespace prefix in child elements in a layout - android

I am trying to use custom attributes in some Android layouts, but I am getting an error (from Eclipse) when I try to use a namespace prefix other than android: in a child element. Note that it works ok when I use the custom: namespace prefix in the root/parent element in the file, just not the child element.
For example, here's a simple layout with the custom namespace specified:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
custom:my_tag1="whatever"> <!-- compiles fine -->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitCenter"
custom:my_tag2="true"/> <!-- generates an error -->
</LinearLayout>
The error that Eclipse gives (only on the second attempt to use the custom: prefix) is:
Unexpected namespace prefix "custom" found for tag ImageView.
If I make my root element an ImageView instead of a LinearLayout, the prefix is accepted. So it seems to be just a problem using the namespace prefix in a child element.
Also, if I try to add another xmlns:custom="http://schemas.android.com/apk/res-auto" attribute to the ImageView, it complains as well.
If it helps, here is the attrs.xml file I'm using with the above:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="my_tag1" format="string"/>
<attr name="my_tag2" format="boolean"/>
</resources>
I've seen some stuff online that leads me to believe what I want to do should be possible. For example, in the accepted answer here, Qberticus uses the prefix "whatever" in a child class. Similarly in the post here.
I don't get it. Is using a non-android namespace prefix just not allowed for child elements, or am I doing something wrong?

It can be ignored, I always did it and I didn't encounter any problems.
To make it go away you need to set the following:
add xmlns:tools="http://schemas.android.com/tools" to your root view
add tools:ignore="MissingPrefix" to your text view
On a side note, however, I usually use custom attributes with custom views :-)

Related

Custom component in Android class library project

We want to create an Android Class Library to reuse some code, mainly custom views.
I have successfully created and referenced the views in Xamarin.Android projects.
The only issue I've got is I cannot use the declare-styleable. The view is looking fine, but can't use custom attributes in the XML layout.
<resources>
<declare-styleable name="MyCustomView">
<attr name="srcLittle" format="reference" />
</declare-styleable>
</resources>
And this is how I use it:
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/res-auto"
[...] >
[...]
<Core.MyCustomView
android:id="#+id/item_proposal_validation_trips_icon"
android:layout_gravity="center"
android:layout_height="48dp"
android:layout_width="48dp"
app:srcLittle="#drawable/ic_plane" /> <-- ERROR
[...]
</android.support.v7.widget.CardView>
Error in XML:
The "http://schemas.android.com/apk/res/res-auto:srcLittle" attribute is not declared
Error compiling:
1: error: No resource identifier found for attribute 'srcLittle' in package 'res-auto'
Thanks.
The namespace you've defined for the app prefix in your layout is incorrect.
xmlns:app="http://schemas.android.com/apk/res/res-auto"
The correct namespace for your app-defined attributes is http://schemas.android.com/apk/res-auto. You've got an extra res/ in there. It should be:
xmlns:app="http://schemas.android.com/apk/res-auto"

Difference between android: and app: prefix in Android XML?

What is the difference and more importantly the necessity of having different prefixes in Andriod view XML?
For example,
<android.support.v7.widget.Toolbar
android:id="#+id/actionToolBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentInsetEnd="20dp"
app:contentInsetEnd="20dp"
android:elevation="3dp"
/>
Has contentInsetEnd for both android and app.
android is usually used for attribute coming from Android SDK itself.
app is often used if you are using the support library.
You may also see other namespaces if you are using custom views (of your own or form a library).
Here is some extra information: http://developer.android.com/training/custom-views/create-view.html#customattr
app namespace is used for custom defined attributes, which are usually defined in /values/attrs.xml Here is a sample of such file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SimpleTabIndicator">
<attr name="numberOfTabs" format="integer"/>
<attr name="indicatorColor" format="color"/>
</declare-styleable>
</resources>
And a sample usage would be
<com.someapp.demo.SimpleTabIndicator
android:id="#+id/tabIndicator"
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="#26292E"
app:indicatorColor="#FFFDE992"
app:numberOfTabs="5"/>
Android namespace you use for Android's widgets and UI controls.
app is just a namespace for any custom parameters for a custom View.
This can be anything but if you see the root element there's probably a line xmlns:app="http://schemas.android.com/apk/res-auto" that assigns the namespace .

Hiding views declaratively based on screen size in Android

In android xml:ish
Is there any way to change a visibility attribute based on the layout size/orientation in the xml directly?
I have a button in a fragment that should be visible for small screens sizes only. On larger sizes, let's say layout-large, I want it to be hidden.
Sure, I can write code for this without any problem but for academic reasons I would like to know it it's possible to do something like this.
<Button
android:id="#+id/btn_check_availability"
style="#style/product_info_footer_button"
android:layout_width="fill_parent"
android:layout_height="35dp"
android:text="#string/check_availability"
android:visibility="<magic expression here>" />
Thanks
// Johan
This answer is based off the explanation provided here by Flávio Faria.
The visible, gone, etc can be values mapped to their corresponding enum values in a string resource - which means you can create a visibilty.xml with string resources for each layout you want, and Android will automatically resolve the one you want for each screen type.
I'd recommend the following:
/res/values/visibilty.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Enum values pulled from Android source -->
<string name="visibility_visible">0</string>
<string name="visibility_invisible">1</string>
<string name="visibility_gone">2</string>
<string name="product_info_footer_button_visibility">#string/visibility_visible</string>
</resources>
/res/values-large/visibilty.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="product_info_footer_button_visibility">#string/visibility_invisible</string>
</resources>
And then you can reference the visibility as follows for your button:
<Button
android:id="#+id/btn_check_availability"
style="#style/product_info_footer_button"
android:layout_width="fill_parent"
android:layout_height="35dp"
android:text="#string/check_availability"
android:visibility="#string/product_info_footer_button_visibility" />
Warning: This depends on the device having the same enum values for visibility (0/1/2) as defined in the AOSP source. Device manufacturers and custom ROM creators can change these values, in which case this code will likely not work as desired.
The android:visibility attribute is an int (like many attributes) so you can do the following :
Define a resource file named visibility.xml in values-port and values-land resource directories. The content of this file is like this :
values-port/visibility.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="buttonvisibility">0</integer> <!-- 0 is the value for android:visible -->
</resources>
values-land/visibility.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="buttonvisibility">1</integer> <!-- 1 is the value for android:invisible -->
</resources>
and in your layout.xml :
<Button
android:id="#+id/btn_check_availability"
style="#style/product_info_footer_button"
android:layout_width="fill_parent"
android:layout_height="35dp"
android:text="#string/check_availability"
android:visibility="#integer/buttonvisibility" />
It works : btn_check_availability is visible in portrait and invisible in landscape.
Note : this example use layout orientation as discriminator, but you can of course do it with any resource qualifier (like dimension, density, ...)
There is no magic expressions available in XML. If only.
There are two approaches to this problem:
a/ use the drawable folder system. Drawable folders can be copied and named to be DPI aware following the conventions dictated here: Supporting Multiple Screens.
b/ Do it programmatically. On runtime check for screen DPI and show/hide view accordingly.
Have you looked at using includes and multiple layouts organized into the appropriate size/orientation layout folders? Some layouts could either simply not have the button or have it hidden by default.
Re-using Layouts with include
Providing Alternative Resources

Cascade the value of a custom attribute from a parent view to a child view?

How do I "cascade" the value of a custom attribute from a parent view to its child view?
This is easiest to explain using an example:
<com.example.CustomLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
app:percent="35" >
<com.example.CustomView
android:id="#+id/customView1"
app:percent="how-to-get-app:percent-value-here???"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</com.example.CustomLayout>
Here, CustomLayout extends LinearLayout. I have defined a custom attribute "percent" in attrs.xml using <declare-styleable> element. As you can see, I set percent to 35 in the XML for CustomLayout.
I now want to pass in the same value to CustomView (which extends View) and which I will include in CustomLayout. I am unable to find a way to do this in XML (it is easy to do this in code though).
I tried the following:
app:percent="#attr/percent"
app:percent="?attr/percent"
Both of these (expectedly) fail with NumberFormatException at TypedArray#getInt().
So, any ideas on how to get this to work?
Although the idea comes a bit late and the method is not straight forward, I think it's still worth sharing. We can put custom attributes into a theme, so the attributes can be passed to all child views from the parent view where the theme is used (i.e., the attributes exist within the View Group).
Example as follows:
<integer name="percentage">35</integer>
<style name="CustomTheme" parent="suitable theme for your case">
<item name="percent">#integer/percentage</item>
</style>
<com.example.CustomLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:theme="#style/CustomTheme" >
<com.example.CustomView
android:id="#+id/customView1"
app:percent="?attr/percent" <!--Note: that's how it refers to the value,
however, re-assign the attribute value here is meaningless as attribute percent
should exist in all child views now. You can retrieve its value via
Theme.obtainStyledAttributes(R.style.CustomTheme, new int[] {R.attr.percent})
in every child view-->
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</com.example.CustomLayout>

Android access attribute reference

In the Android resources xml to reference the value of an attribute for a theme you use the question-mark (?) instead of at (#). Such as ListViewCustomStyle below:
<ListView
android:id="#+id/MainScreenListView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
style="?ListViewCustomStyle"/>
How can I use the value of the ListViewCustomStyle in code? If I try it the normal way i.e.
com.myapp.R.attr.ListViewCustomStyle
Then the code crashes. Is there a special way to access this since it is a reference to an item and not an actual item?
It might just be crashing because you wrote ListRowCustomStyle there, and ListViewCustomStyle in your xml.
The way I do this is to have the tag style="#style/my_button" for example (with no android: preceding it). Then you can define your style in the values/styles.xml file, e.g.
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="my_button" parent="#android:style/Widget.Button">
<item name="android:gravity">center_vertical|center_horizontal</item>
<item name="android:textColor">#FFFFFFFF</item>
...
</style>
</resources>
You can access the style in code by using the id R.style.my_button
I believe in the xml you wanted to write
style="#style/ListViewCustomStyle"
Anyway, how to use it in code?
Last time I check, it was impossible :(
I did it with a trick:
create a layout file as the example that follows:
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
style="#style/MyCustomStyle"/>
when you want to add an object with your custom style in code, you have to inflate it, using this layout you just created:
:
LayoutInflater inflater = LayoutInflater.from(this); // this = activity or context
Button button = (Button) inflater.inflate(R.layout.myButtonWithMyStyle, null); //use the same layout file as above
button.setText("It works!");
myView.addView(button);
This is considerably slower than creating a Button in code. It may be a problem if you create hundreads of Views at the same time using this method. Less than that I think you can handle it.

Categories

Resources