Android Studio reusable xml value - android

I've got this super simple question I can't find an answer to.
I want to make a variable which I could then use for multiple elements.
Something like this in strings.xml:
<resources>
<string name="textSize">20sp</string>
</resources>
...
<EditText android:textSize="#string/textSize" />
But this does not work.
I was able to accomplish what I wanted the following way in themes.xml:
<style name="textSize">
<item name="android:textSize">20sp</item>
</style>
...
<EditText android:theme="#style/textSize" />
But it seems too complicated for just a single value, is there a better way?

As suggested in the comments, this looks like a dimen property rather than a string.
Just like strings.xml, you can have another file (usually dimen.xml) with dimensions. Your case could look like this:
<resources>
<dimen name="bigText">20sp</string>
</resources>
It also allows you to have different settings for different configurations (for example, screen sizes here: How to define dimens.xml for every different screen size in android?).
You can find the documentation here:
https://developer.android.com/guide/topics/resources/more-resources?hl=en#Dimension

Related

Create a different directory other than res/values/styles.xml to define styles

As I asked in the title, is there any way to do so?
Now, when I put all styles into one file it looks a little crowded, I would like to separate styles.
For example:
res/values/styles_for_main_screen
res/values/styles_for_set_screen
And then in main_screen layout
<TextView
style="#styles_for_main_screen/text_view_custom_style">
</TextView>
This example obviously doesn't work, but it shows what I'd like to achieve.
I read in every tutorial that we need to put our custom styles into styles.xml file, but I wonder if there is a possibility to diversify styles in few xml files?
Every question I read was something like "how to do .... in styles.xml".
I can't find question similar to mine.
Example how it should be done, thanks #Frank N. Stein for the answer:
This how looks my custom xml res/values/styles_for_main_screen
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="custom_back">
<item name="android:background">#E81C1C</item>
<item name="android:text">whatr</item>
</style>
</resources>
and then to retrieve this style I just write:
<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
style="#style/custom_back"
/>
so the convention looks like:
style="#(what I want to retrieve)/(name of style)"
from the android developers site
In XML: #[package:]style/style_name
You can call your style files whatever you want (if you respect the naming conventions and you put them all in the values folder/s), as you do with strings and colors.
Therefore, YES! You can have multiple ones, if so you desire.
Obviously, you will NOT specify the path to each file.
Referencing the style/s by using R.style.your_new_style is enough.
Remember that, android scans the files found int the /values directory by reading their content. For styles, every <style name="styleName" > ... </style> will be parser and a style object reference will be created.
Then, as Frank said, Yes. You can use whatever file name to write your custom styles.

How to set text size for app in one place?

I want to be able to set the text size on an application wide basis.
So I will need to be able to access the value in code and xml.
I tried putting the size in my dimens.xml as follows...
<item name="text_size_small" type="dimen" format="float">15.0</item>
But I was unable to re-use this in xml i.e...
android:textSize="#dimen/text_size"
Gives an exception...
android.view.InflateException: Binary XML file line #29: Error inflating class RadioButton
Also I think I would need to specify the units i.e 'sp' in this case.
So is there a way to do it?
If not, i will probably have to set all text size's that need setting, programmatically.
Hopefully someone knows a better way.
inside dimens.xml, you can use the <dimen item, and specify the unit:
<dimen name="text_size_small">15sp</dimen>
to access it programmatically, you
textview.setTextSize(getResources().getDimension(R.dimen.text_size_small), TypedValue.COMPLEX_UNIT_PX);
in dimens the size is already scaled for the unit, so you don't need to apply the conversion again, hence the TypedValue.COMPLEX_UNIT_PX
In your dimens.xml specify your like this
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="text_size_small">15sp</dimen>
</resources>
In your layout use this
android:textSize="#dimen/text_size_small"
If you want to set this programtically, try like this
textview.setTextSize(getResources().getDimension(R.dimen.text_size_small));
You must define own textview style.
#styles
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light">
<item name="android:textViewStyle">#style/CMTextView</item
</style>
<style name="CMTextView" parent="android:style/Widget.TextView">
<item name="android:textSize">#dimen/text_size</item>
</style>
#dimens
<dimen name="text_size">18sp</dimen>

Application branding

I would like my application to be available under different brandings - this means that it must be possible to easily change background bitmaps in few places, but also change text resources.
My plan is to use themes and styles, I know they can be used for switching bitmaps but will they allow me to change also texts in TextViews for example?
Is it also possible to specify in style or theme a text identifier and later dynamically read it in code?
[EDIT]
After some investigation, of course texts can be substituted with styles. Another problem that comes with application branding is the need to change package name - otherwise Google Play wont accept our branded application.
[EDIT]
After more investigation, below I include small sample on how to add two switchable themes that will allow to substitude drawable in activity layout, and text resource in textview. Whats left is to call setTheme(R.style.Theme1); or setTheme(R.style.Theme2); in onCreate before setContentView.
<-- attrs.xml />
<resources>
<attr name="ProductName" format="reference"/>
<attr name="ProductBackground" format="integer"/>
</resources>
<-- styles.xml />
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="Theme1" parent="android:Theme.Light">
<item name="ProductName">#string/s_product_1_name</item>
<item name="ProductBackground">#drawable/back_1_vga</item>
</style>
<style name="Theme2" parent="android:Theme.Light" >
<item name="ProductName">#string/s_product_2_name</item>
<item name="ProductBackground">#drawable/back_2_vga</item>
</style>
</resources>
<-- my activity layout />
<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:background="?ProductBackground"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
tools:context=".MainActivity"
android:background="#ff0000"
android:text="?ProductName"
/>
</RelativeLayout>
There are two aproaches to make different brandings of you app:
1) Split your app into multiple library projects, common code is in lets say common_lib library project, and all your brandings are in separate projects using common_lib but changing some of the resources, like strings, some drawables, also package name. This is the aproach we have choosen in our app.
2) Use gradle product flavors: http://developer.android.com/sdk/installing/studio-build.html, I think this should now be the prefered solution.

Android style descriptions

I tried changing the appearance of a spinner and I partly succeeded. I'm doing this via overriding parts of the theme. I managed to change the text size of the spinner item (i.e. the text size in the drop down button) with my themes.xml and styles.xml:
My themes.xml file looks like this:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="CustomTheme" parent="#android:Theme.Holo.Light">
<item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:spinnerItemStyle">#style/CustomSpinnerItem</item>
</style>
</resources>
My styles.xml file looks like this:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="CustomSpinnerItem" parent="#android:Widget.TextView.SpinnerItem">
<item name="android:textAppearance">#style/CustomTextAppearance</item>
</style>
<style name="CustomTextAppearance">
<item name="android:textSize">30dp</item>
</style>
</resources>
However I cannot find the attributes that are responsible for the text appearance of the items in the dropdown list of the spinner. I tried dropDownItemStyle amongst other things. In my opinion the attribute names are not self-explanatory, so I wanted to know whether there is a documentation of what attribute does what in a style to find out which attributes to override. I found it very cumbersome to trace back all the styles used in a theme via the themes.xml and styles.xml of the platfrom and then try to find the right attributes via trial and error.
I know that one can change the appearance by passing layouts to the adapter, however, this is not really what I was looking for, since (as far as I know), you can only use inheritance in styles and not in layout xml files. If I created a custom layout for the adapter I'd have to create 9-patch images etc., which I think is a bit too time consuming in case I only want to change the text size.
Of course it's possible that I misunderstood the whole concept, since I'm new to Android ;)
You probably have found out the answer since you asked but for others looking at similar questions:
I do not know of a list of attribute names with good explanation of what they do (R.attr's page mostly gives information that is already in the name) but the way I do it is:
Start from the element I give to setDropDownViewResource(), in my case: android.R.layout.simple_spinner_dropdown_item and find.
Find its layout definition in \sdk\platforms\android-17 (specific platform version to avoid redundant results).
Get its style from the layout file. In this case: ?android:attr/spinnerDropDownItemStyle
We now have the attribute name we need.
It's better to do it that way rather than try to guess what attribute to use because you know which attribute the system itself use so it's very likely to be the correct one (unless there's a bug).
If I created a custom layout for the adapter I'd have to create
9-patch images etc.
Well, no, the layout determines what kind of GUI element you would have (a textfield, a spinner, an imagebutton, a custom element...), not how they are styled (nine-patch backgrounds, text colors...), so you still would have to mess with styles to get the right appearance.
For example, for visual consistency I ported the button, checkbox and spinner style from Theme.Holo to Gingerbread, yet I did not mess with layout, all I did was the aforementioned steps plus looking up the result (spinnerDropDownItemStyle in the above example) in themes.xml, which gave me the style name (e.g.: Widget.Holo.DropDownItem.Spinner).
Then I looked that up in styles.xml and imported it (and any parent*) in my project's styles.xml, searching and copying any Holo specific reference in my project and adjusting the namespace accordingly (add android: to attributes and replace ?android:attr with #style for what I copy to my styles.xml file).
So far I haven't had to mess with layouts at all (even the presence of radio buttons in spinner dialogs on Gingerbread is determined by an xml attribute: android:checkMark).
If a style has no parent attribute (like Widget.Holo.DropDownItem.Spinner) then its parent is the same style minus the last element (e.g.: Widget.Holo.DropDownItem)

How to use a theme defined variable in res/values/dimens.xml?

Howdy.
In my themes.xml definition, I have the following:
<style name="mythemename">
<item name="d_myvar">100dip</item>
</style>
I would like to be able to reference this in res/values/dimens.xml like so:
<dimen name="myvar">?d_myvar</dimen>
Alas, this doesn't work. When I try to use the #dimen/myvar as the height of a LinearLayout, the app crashes with the error "You must supply a layout height attribute."
I have also tried
<dimen name="myvar" value="?d_myvar" />
But that won't compile.
How can I define #dimen/myvar in my xml so that it loads the ?d_myvar variable defined in the theme?
Thanks!
I saw your help request on the Italian Startup Scene.
Unfortunately, according to the syntax of the dimen tag:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen
name="dimension_name"
>dimension</dimen>
</resources>
you simply can't do it. In fact, you can reference theme attributes when the syntax specifies:
?[package:][type:]name
Solutions:
Gix's answer would be the standard way of defining and reusing dimensions.
Maybe you can reorganize your code to reuse d_myvar through inheritance?
As a last and desperate resort, I would go for a shell script that automates the process of variable substitution using xml command line tools. I have never personally used them, but see for example xmllint, xmlstarlet or this article.
Put the 100dip part in your dimens.xml like so:
<dimen name="myvar">100dp</dimen>
then in your theme you can reference it as #dimen/myvar if you need, or you can reference it in code using R.dimen.myvar
In other words, you don't set the dimension in theme and then reference it in dimens.xml, but you go the other way around. You set the dimension in dimens.xml and then reference that in your theme/style xml.
In styles.xml
<resources>
<attr format="dimension" name="exampleDimension"/>
<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
<item name="exampleDimension">100dp</item>
...
</style>
</resources>
Then in your other xml to use the new attribute, you would use it like this
android:padding="?attr/exampleDimension"

Categories

Resources