40

I have a layout that contains two ImageViews. I want one of them to be visible in portrait and the other in landscape. How do I achieve it using resources? (I know how to set it programmatically for but this specific use I need to achieve it using resources).

I tried something like

in res/layout/may_layout.xml:

...
<ImageView
      android:id="@+id/image1"
      android:visibility="@integer/visible_in_portrait"   <<-- is this allowed?
      ...
/>
<ImageView
      android:id="@+id/image2"
      android:visibility="@integer/visible_in_landscape"   
      ...
/>

in res/values/integers.xml:

...
<!-- NOTE: 0 and 8 are VISIBLE and GONE respectively -->
<integer name="visibile_in_portrait">0</integer>
<integer name="visibile_in_landscape">8</integer>

in res/values-land/integers.xml:

...
<integer name="visibile_in_portrait">8</integer>
<integer name="visibile_in_landscape">0</integer>

But I get a runtime error (index out of bound) when trying to inflate the images. When I remove the android:visibility statements, the program runs but I see both images.

Q: What is the way to use a resource as a value for the android:visibility attribute?

(if you wonder why setting it programmatically will not help me, it has to do with automatic landspace/portrait switch of app widgets with file uri bitmaps).

user1139880
  • 1,828
  • 3
  • 18
  • 27

3 Answers3

66

This is an old question that has already been accepted, but the following solution may help someone else:

If you check res/values/attrs.xml in Android source code, you'll see the definition of visibility property like this:

 <!-- Controls the initial visibility of the view.  -->
    <attr name="visibility">
        <!-- Visible on screen; the default value. -->
        <enum name="visible" value="0" />
        <!-- Not displayed, but taken into account during layout (space is left for it). -->
        <enum name="invisible" value="1" />
        <!-- Completely hidden, as if the view had not been added. -->
        <enum name="gone" value="2" />
    </attr>

This attribute expects a string value (visible, invisible, gone) that will be converted to (0, 1, 2) respectively. So, you can declare integer resources containing these values like this:

values/integers.xml

<integer name="visible_in_portrait">2</integer> <!-- This is GONE -->

values-land/integers.xml

<integer name="visible_in_landscape">0</integer> <!-- This is VISIBLE -->

However, if you want to make it even better in order to stop guessing these numeric constants every time, you could do like this:

values/integers.xml

<!-- These are alias for the constants we'll reference below -->
<integer name="view_visible">0</integer> <!-- This is VISIBLE -->
<integer name="view_invisible">1</integer> <!-- This is INVISIBLE -->
<integer name="view_gone">2</integer> <!-- This is GONE -->

<integer name="visible_in_portrait">@integer/view_gone</integer> <!-- We're referencing the visibility alias we declared above -->

values-land/integers.xml

<integer name="visible_in_landscape">@integer/view_visible</integer>

You can use this approach or the one suggested by Keyhan. Choose the one that fits you better.

Flávio Faria
  • 6,575
  • 3
  • 39
  • 59
  • 5
    It also works declaring them as `` rather than `` – TalkLittle Jan 01 '14 at 05:22
  • the good practice would be to keep the original android values for visible, invisible and gone (not 0, 1, 2, but 0, 4, 8) – Bartek Lipinski Aug 19 '14 at 10:55
  • 4
    Well, that's not exaclty how it works. If you check the `View` class code, these values (0, 1 and 2) are used to access the positions of this member: `private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE};`. That's why you can't use 0, 4 and 8, because 0, 1 and 2 stand for VISIBLE, INVISIBLE and GONE indices. – Flávio Faria Aug 19 '14 at 14:43
  • Aliases doesn't work for me (i.e. `view_visible`). It only works if I assign 0, 1, 2 to an integer resource that I use directly. (but +1 for that bit!!) – charles-allen Nov 25 '17 at 10:19
  • From `android.view.View#VISIBLE``android.view.View#INVISIBLE` and `android.view.View#GONE` values of variables should be ` ` – NickUnuchek May 14 '19 at 14:03
28

it will be possible when you use this trick, add your visibility line to a style and put two instances of that file in -land and normal mode.

I mean in file styles.xml in folder values put a style with name s1, and put android:visibility=visible in that, and in styles.xml in folder values-land put a style with name s1, and put android:visibility=gone.

also, in file styles.xml in folder values put a style with name s2, and put android:visibility=gone in that, and in styles.xml in folder values-land put a style with name s2, and put android:visibility=visible.

and then, set s1 to first imageview and s2 to second.

solution given by dear Calvin is also correct, but when you have a complex layout that may change during time, having one layout file would be better, and will have less need to change.

Kayhan Asghari
  • 2,817
  • 1
  • 28
  • 47
  • Thanks Keyhan, I will give it a try and report here. Will this approach also help with this question? http://stackoverflow.com/questions/9745227/setting-programmatically-the-pixel-size-of-a-remote-imageview . I have 5 different sizes times two modes (portrait and langscape). Use the style also to control the ImageView size? This way I will have a single layout with two images and 5 pairs of orientation/portrait styles. (working around the limitations of RemoteViews is not fun ;-)). – user1139880 Mar 17 '12 at 18:08
  • Works well. This was a great help!. Thanks Keyhan. – user1139880 Mar 17 '12 at 19:08
  • The suggested solution involves the usage of [Style Resources](http://developer.android.com/guide/topics/resources/style-resource.html) – denispyr Jun 16 '13 at 21:28
  • 1
    Creating a whole style just to set an attribute is not a good practice, especially if you need to set more attributes in styles already (you can't have two styles on a view). [Flávio's answer](http://stackoverflow.com/a/14358801/253468) is much cleaner. – TWiStErRob Apr 24 '15 at 12:21
0

It is not possible. (I tried define fill_parent as string and use it for layout_width and it fails too.)

Why don't you use 2 layouts?

  1. res/layout/may_layout.xml
  2. res/layout-land/may_layout.xml

Which each define the correct imageview to show.

In addition, having values-land may cause you problem when you needs to support multi-languages. (You will need to have value-xx-land for each language)

Calvin
  • 3,302
  • 2
  • 32
  • 41
  • 1
    Thanks Calvin. I was trying to avoid duplicating the layout, unless I can generate them automatically from a template at build time. Don't know if eclipse supports it and how standard it will be. – user1139880 Mar 17 '12 at 18:04