For instance, in a specific layout I have the following XML:
<GridView
android:id="#+id/gridView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="3dp"
android:columnWidth="48dp"
android:numColumns="auto_fit"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:stretchMode="spacingWidth" />
This grid view is specific to this layout and I don't think I'll be using any other grid views with similar properties. That to say that the dimension values in the code are specific to that grid view.
Should I still move them to a dimens.xml file or it's fine to just leave them like that? If so, should I place values in the dimens.xml file only when that value is used across multiple layouts?
I drop dimension values into a dimens.xml resource typically for three reasons:
Reuse: I need multiple widgets or layouts to use the same value and I only want to change it once when updating or tweaking across the application.
Density Difference: If I need the dimension to be slightly smaller or larger from ldpi -> hdpi or small -> large.
Reading in from code: When I'm instantiating a view in the code and want to apply some static dimensions, putting them in dimens.xml as dp (or dip) allowing me to get a scaled value in Java code with Resources.getDimensionPixelSize().
Supplemental answer
#Devunwired lists 3 reasons to use dimens.xml. Here are the details of how to do that.
1. Reuse
If you set some dp or sp value in dimens.xml once like this
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="textview_padding">16dp</dimen>
<dimen name="large_text_size">30sp</dimen>
</resources>
you can reuse it throughout your app in multiple locations.
<TextView
android:padding="#dimen/textview_padding"
android:textSize="#dimen/large_text_size"
... />
<TextView
android:padding="#dimen/textview_padding"
android:textSize="#dimen/large_text_size"
... />
Then when you need to make a change, you only need to do it in one place.
Notes
This is basically the same effect as using a style or theme.
Be careful not to give two different views the same dimen value if they really shouldn't be. If you need to make changes to one set of views but not another, then you will have to go back to each one individually, which defeats the purpose.
2. Size Difference
#Devunwired called this Density difference, but if you are using dp (density independent pixels), this already takes care are the density difference problem for all but the most minor cases. So in my opinion, screen size is a more important factor for using dimens.xml.
An 8dp padding might look great on a phone, but when the app is run on a tablet, it looks too narrow. You can solve this problem by making two (or more) different versions of dimens.xml.
Right click your res folder and choose New > Value resource file. Then write in dimens and choose Smallest Screen Width. Write in 600 for the width (7” tablet). (There are other ways of choosing the sizes. See the documentation and this answer for more.)
This will make another values folder that will be used for devices whose smallest screen width is 600dp. In the Android view the two dimens.xml files look like this.
Now you can modify them independently.
values/dimens.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="my_default_padding">16dp</dimen>
</resources>
values-sw600dp/dimens.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="my_default_padding">64dp</dimen>
</resources>
When using your dimen you only have to set it with the name you used in both dimens.xml files.
<LinearLayout
...
android:padding="#dimen/my_default_padding">
</LinearLayout>
The system will automatically choose the right value for you depending on the device the user is using.
3. Reading in from code
Sometimes it is a pain scaling programmatically between px and dp (see this answer for how).
If you have a fixed dp value already defined in dimens.xml like this
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="my_dp_value">16dp</dimen>
</resources>
Then you can easily get it with
int sizeInPixels = getResources().getDimensionPixelSize(R.dimen.my_dp_value);
and it will already be converted to pixels for whatever density device the user has.
The dimens.xml file is used to keep all the hard-coded pixel values in one place.
Now, although you may not repeatedly use these values right now, it's still a good idea to to place them in dimens.xml for future reference. Besides, following a standard Android programming paradigm helps other developers to understand your code faster. This is much like the strings.xml where we place Strings some of which end up being used only once! :)
I don’t know if it can help you but I wrote a little java programe that allows you to duplicate a dimension xml file with a new desired value so that you no longer have to do it by hand line by line.
https://github.com/Drex-xdev/Dimensions-Scalable-Android
Related
I want to ensure a consistent UI across all screen sizes. I'll use the bottom margin as an example. Let me illustrate with the picture below:
I could hardcode 50dp into the xml for the bottom margin as shown in the picture and treat it as a "middle ground" between large and small devices. Or, I could determine dynamically on runtime the parent view's height, and then multiply it with, say, 10 % and then implement it that way although it's a bit more of a hassle. What do you recommend?
In my opinion, you don't need to set margins as percentage for a beautiful UI. Margins should stay same as long as you are not showing different UIs for different screen sizes.
Using XML for dimensions is generally the best way. It helps you to keep the code clean. If you need different values for different cases (such as device size, orientation, density), you can use variations of XML files (e.g. values-large for larger screen sizes). Just don't include hard-coded values in your layout XML, try to extract them into values files. For example use a layout XML like:
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="#dimen/margin_bottom" />
and create two dimens.xml files under values and values-large folders:
values/dimens.xml
<resources>
<dimen name="margin_bottom">16dp</dimen>
</resources>
values-large/dimens.xml
<resources>
<dimen name="margin_bottom">32dp</dimen>
</resources>
I think its better to give a margin in xml, also you can specify a bigger one for tablets in layout-sw600dp/ and layout-sw720dp/.
Btw, you don't need to dynamically determine the height of the screen in your second approach. You can specify a parent linear layout with orientation vertical and with a weightSum = 10 for example. Then you create your child views with layout_weights (the sum of weights should be 9.5 in this example), and for the bottom margin you can create an empty view with 0.5 layout_weight. So this way, the ratio will be fine on every screen.
I've been developing apps for months and I've read that using layout-small, layout-large, layout-xlarge and so on to support multiple screen resolutions is deprecated started in Android 3.0(correct me if I'm wrong). Hence, I'm still using multiple layout directories but it's a lot of work when designing an Application.
My questions are:
Is there any way to design a layout to support multiple screens all at once without using multiple layout-size.xml files?
What is the alternative solution when using layout-size directory is deprecated?
You can use dimensions. Basically, you'll have the same thing, with multiple directories, but for the values directory, thus a values, values-sw600dp, values-sw600dp-land etc.
In these, you can have a dimens.xml, with the following content:
<!-- In values/dimens.xml -->
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="my_specific_dimension">150dp</dimen>
//More items...
</resources>
<!-- In values/dimens.xml -->
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="my_specific_dimension">150dp</dimen>
//More items...
</resources>
You can now use #dimen/my_specific_dimension in a single layout file, for example for a width or a height, and it will use, just like for the multiple layouts situation, the correct dimension based on the screen category.
That works only if the layout is basically the same, with different sizes. There's little customisation with that solution. If you want to use different layout, you still have to write multiple layout files. I believe the deprecation of x-large, etc. was after they introduce layout-sw600dp, layout-land, layout-sw600dp-land. Check the documentation for how to declare different layout for different sizes. It explains how to use the sw<N>dp qualifiers.
Unfortunately, there is not a standard layout that supports multiple screens.
For instance Normal layout can display with several inches, and accordingly may be among them some larger height or width. However, it should define be unique layout for each screen.
How can I set margins(Left,Top,Right,Bottom) to these ImageView so that it will display correctly on multiple screen sizes in Android ? Also I need to handle click events on these Images.1
Well the whole point of using DP is so that you don't have to worry about this. Margins will be roughly the same across devices, but if you're relying on lining things up on one particular device resolution/density combination, you'll definitely be in for a surprise when you test on other devices.
That said, if you do need to specify different margins for different screen sizes, simply add an XML file in res/values -- something like dimens.xml:
<resources
xmlns:android="http://schemas.android.com/apk/res/android"
>
<dimen name="my_view_margin">10dip</dimen>
</resources>
Then add one of these XMLs for every specific device qualifier that you need to (e.g. values-large, values-sw600dp, values-xlarge, etc.) and modify the value as you see fit. When you want to use these dimensions in a layout, just use:
android:layout_margin="#dimen/my_view_margin"
And Android will pick the correct value for whatever device it happens to be running on.
provide different values folders and set values.
For Ex.
values,
values-sw350dp,
values-sw480dp,
values-sw600dp,
values-sw720dp etc.
I want to use different font size for different screen sizes.
I read about this many articles, but I'm not sure about usage. Is correct to use different dimens resource file for different screen dimensions like code below:
res/values/dimens.xml
res/values-small/dimens.xml
res/values-normal/dimens.xml
res/values-xlarge/dimens.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="text_size">18sp</dimen>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="text_size">24sp</dimen>
</resources>
...
I also read that correct way is to use sp for font size, but this doesn't fit font in different screen dimensions as I expect.
If there, what are the disadvantages of using different dimens for every size?
Thanks
The best way is to create different layout resources for each of the screens you wish to support. Place each of the layouts in a separate folder that designates the width of the screen. For example, normal sized layouts go in your res/layout folder, and a layout resource for a 7 inch tablet (600 pixel width) would go in the res/layout-sw600dp folder. Make the resource names identical, but adjust your font sizes accordingly.
#up Not, it isn't good way.
#topic You can gets width & height of screen (and w&h of View). Next, you can set font, for example 2% of width screen. If you have content 1260x720, 0.02*1260=24,6 px (you can use also (int)24.6 to convert double to int)
I do something very similar and it's worked fine for me. Some people put the values in the various layouts such as Fietser suggested, but if all of your layouts end up being the exact same except for the font size, your approach is better. That way you can have a single layout and only modify the font sizes. But sometimes you might have changes in the actual layout xml, so then it's probably a wash between the two approaches.
In my layout XML files, I reference a lot of parameters through a separate files called dimens.xml.
For example, dimens.xml contains parameters like these:
<dimen name="textSize_normal">20dp</dimen>
<dimen name="buttonTextSize_normal">15dp</dimen>
<dimen name="editTextSize_normal">17dp</dimen>
<dimen name="buttonHeight_normal">37dp</dimen>
<dimen name="margin_normal">5dp</dimen>
And in my main.xml, for example, I would set the text size for a TextView by doing something like this:
android:textSize="#dimen/editTextSize_normal"
It works great.
Now, my questions is, is it possible to set the values for the dimen variables in my dimen.xml file programmatically from my main activity? What I am trying to do is fetch the screen size, and set, for example, the textSize based on a fraction of the height of the screen so that it is easily adaptable to any screen size. I have all that figured out, I just need your help to figure out how to set the dimen variables in my code.
Now, my questions is, is it possible to set the values for the dimen variables in my dimen.xml file programmatically from my main activity?
No.
What I am trying to do is fetch the screen size, and set, for example, the textSize based on a fraction of the height of the screen so that it is easily adaptable to any screen size.
Ignoring that this is an odd UI approach, the way to do that is to delete your android:textSize attributes and to change the text size at runtime using setTextSize() in Java.
I have all that figured out, I just need your help to figure out how to set the dimen variables in my code.
You don't "set the dimen variables". You apply your calculations to the widgets, via setters like setTextSize().
No, you can't edit the Resources files on runtime, they are already compiled and generated.
You should use density independent pixels in all your resources, so that dimensions can adapt to screen size. You don't need to calculate that values at runtime. If you want to have a different layout for different screen sizes, then consider using multiple resource files.
Read this guide.
i guess what you mean is to change the size depending on the device's screen size..
which can be made by creating multiple dimens.xml files in folders like values-hdpi, values-xhdpi, values-xxhdpi, values-mdpi,.. and then on runtime the compiler will choose the dimen depending on the dpi
i actually didn't try this before but i read it
here.. take a look at this:
http://developer.android.com/guide/practices/screens_support.html#qualifiers