29

There are a activity what I want to fill the screen in a phone and pop up(dialog) for a tablet.

I thought I make a layout file like this,

<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="@dimen/main_layout_width"
  android:layout_height="match_parent">

and externalize the value of width as

in values/dimens.xml

<dimen name="tutorial_width">match_parent</dimen>

in values-xlarge/dimens.xml

<dimen name="tutorial_width">320dp</dimen>

But I can't representation 'match_parent' as dimen element. Any help? Thanks!

Shakra
  • 291
  • 1
  • 3
  • 3
  • I'm confused. Why not just use "match_parent" for this in the first place? – DeeV Jul 28 '11 at 13:00
  • Whats your minimum API-level? match_parent got introduced in API 8, was called fill_parent before. (I still don't get the idea behind that change) –  Jul 28 '11 at 13:02
  • First of all, 320dp means background image's width. In tablet, the activity's theme is dialog, so it will be shown like popup window. Then if layout_width is match_parent(fill_parent), image is stretched. So I wanna fix the width in tablet. Minimum API-level is 7 and Target API-level is 13. – Shakra Jul 28 '11 at 13:09
  • Since the minimum API is 7, did you try to just use fill_parent instead of match_parent (should be backward compatible with higher API versions anyway)? –  Jul 28 '11 at 14:42
  • +1 for trying configuration-specific dimens, but, as you found, you have to define dimens with numeric values. Android wants you to use configuration-specific layouts as per the answer from @zenob. – cdhabecker Jul 28 '11 at 16:57

9 Answers9

19

The best way I found: - instead of "match_parent" and "fill_parent" write "-1dp" - instead of "wrap_content" write "-2dp"

pjanecze
  • 3,145
  • 3
  • 21
  • 28
  • 12
    This works well for me. I also defined the following two dimensions to make the code more readable: `-1dp -2dp` - then you can use `@dimen/match_parent`. – Ralf Sep 05 '12 at 14:34
  • 7
    This doesn't work for all devices because -1dp is density dependent. – James Wald Oct 18 '13 at 22:53
  • 1
    This **only** works on mdpi devices, as the values remains -1 and -2, which are the respective reserved values. Please don't use this! – Paul Lammertsma Apr 02 '14 at 10:42
  • 2
    This does not work on Samsung Galaxy S5, see James Wald's answer for an explanation – alexbirkett Apr 24 '14 at 06:25
  • 1
    This doesn't work anymore on very high density devices with xxxhdpi like the Nexus 6 or the droid turbo. – Moritz Nov 17 '14 at 21:34
  • If -1dp is not good.. what good option we have? having resolution specific layout just for this one value? – Elye Jan 20 '16 at 00:23
16

dp depends on the device display metrics and won't work on all devices without a set of density-specific overlays, however, px can be used instead.

Unfortunately, the simple rounding technique used by TypedValue#complexToDimensionPixelSize() only considers non-negative values:

final int res = (int)(f+0.5f);
if (res != 0) return res;
if (value == 0) return 0;
if (value > 0) return 1;
return -1;

When f (the px value) is negative, the result is usually rounded incorrectly because it always uses addition. The following pixel sizes are observed for negative px dimensions:

0px = 0.0
-1px = -1.0
-2px = -1.0
-3px = -2.0
-4px = -3.0
-5px = -4.0
...

I opened an AOSP issue for this method:

TypedValue#complexToDimensionPixelSize() rounds negative dimensions incorrectly

Considering this behavior, the following values will work on all devices:

<dimen name="match_parent">-2px</dimen>
<dimen name="wrap_content">-3px</dimen>

You can use -1px or -2px for match_parent, but wrap_content must be -3px. Either combination works on devices and emulators.

In practice, I've found that IntelliJ's Preview feature fails to render layouts when -1px is used for match_parent, and incorrectly renders -2px as if it were "wrap_content" when referenced by another dimension e.g. <dimen name="my_width">@dimen/match_parent</dimen>. I have opened an issue for IntelliJ IDEA:

Android Preview cannot render layout_width="-1px"

James Wald
  • 13,626
  • 5
  • 52
  • 63
  • If [TypedValue#complexToDimensionPixelSize() rounds negative dimensions incorrectly](https://code.google.com/p/android/issues/detail?id=61222&thanks=61222&ts=1382148635) gets fixed, is it going to break using -2px for match_parent and -3px for wrap_content? – alexbirkett Apr 24 '14 at 06:35
  • I wouldn't worry about that method's behavior being changed. It never should have accepted negative inputs, but it's too late to do anything about that now. It would be nice if the implementation of was updated to use a new method that converts negative dimensions correctly, but I doubt that a change like that would be accepted into the AOSP source code. – James Wald Apr 25 '14 at 20:20
12

I used a style to fix this problem. Having separate xml style elements with android:layout_width items for different screen sizes solved the problem without using the undocumented -1dp

urandom
  • 1,147
  • 2
  • 12
  • 21
  • 2
    It's value actually is documented so it's safe to use -1. http://developer.android.com/reference/android/view/ViewGroup.LayoutParams.html#MATCH_PARENT – James Wald Oct 18 '13 at 22:33
  • 2
    This is a way cleaner solution. An example would have proved your point though. – Myles Bennett Mar 13 '14 at 17:14
3

I am not able to comment yet so i'm writing new answer. I used answer provided by @pjanecze in my project. All was fine till few days ago when suddenly some devices started to report strange widget positioning. Devices with very high density, instead of getting match_parent as -1 from my dimenstions (which was equivalent to android constant match_parent = -1 in layout parameters), it was getting -2, which means that width was set to wrap_content (-2 in layout_parameters). Obviously because -1dp is converted to pixels in runtime, and -1dp was in some cases -2px.

So ... instead of using constant -1dp and -2dp, you should use -1px and -2px for match_parent and wrap_content.

vaske
  • 398
  • 1
  • 3
  • 13
3

Whats works for me and probably features academic correctness is something like this:

<!-- In values/dimens.xml -->
<item name="width_match_unless_huge" type="dimen" format="integer">-1</item>

<!-- In values-sw600dp/dimens.xml -->
<item name="width_match_unless_huge" type="dimen" format="dimension">600dp</item>

This allows you to mix sizing behavior constants like MATCH_PARENT and concrete sizes in dp depending on the current configuration.

You would use it as a regular <dimen/>:

<LinearLayout
    android:layout_width="@dimen/width_match_unless_huge"
    .../>
Doodler
  • 167
  • 1
  • 7
3

According this great contribution: http://blog.danlew.net/2015/01/06/handling-android-resources-with-non-standard-formats/

  1. Let's try defining both match_parent and wrap_content without a format:

    <item name="match_parent" type="dimen">-1</item>
    <item name="wrap_content" type="dimen">-2</item>
    
  2. We can reference those in any other dimension value:

    <!-- Inside /res/values/dimens.xml -->
    <dimen name="responsive_width">@dimen/match_parent</dimen>
    
    <!-- Inside /res/values-sw800dp/dimens.xml -->
    <dimen name="responsive_width">800dp</dimen> 
    

For more info visit the web page I mentioned earlier!

Ricard
  • 1,223
  • 1
  • 13
  • 17
0

As mentioned earlier in https://developer.android.com/reference/android/view/ViewGroup.LayoutParams.html#MATCH_PARENT MATCH_PARENT = -1 and WRAP_CONTENT = -2. Instead of declaring the values as Dimension resources I have successfully declared and used them as Integer resources. So for the example to work you can use two Integer resource files:

values/integers.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <integer name="tutorial_width">-1</integer>
</resources>

values-sw600dp/integers.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <integer name="tutorial_width">-2</integer>
</resources>

And the layout file will be:

<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="@integer/tutorial_width"
  android:layout_height="match_parent">
dmanargias
  • 2,626
  • 1
  • 13
  • 7
0

Value -1 was not working for me on android api 30 emulator of Pixel 4.

Clean solution is to define sw600dp/styles.xml and create base style for your component in styles f.e. DialogControllerTypeGridBase then create other that ha its as parent DialogControllerTypeGrid and also other in sw600dp.

Example:

styles.xml

<style name="DialogControllerTypeGridBase" parent="CSGridMatch">
    <item name="android:layout_height">wrap_content</item>
    <item name="android:background">@drawable/background_bordered_section</item>
    <item name="android:horizontalSpacing">8dp</item>
    <item name="android:padding">4dp</item>
    <item name="android:verticalSpacing">8dp</item>
</style>

<style name="DialogControllerTypeGrid" parent="DialogControllerTypeGridBase">
    <item name="android:layout_width">wrap_content</item>
    <item name="android:numColumns">6</item>
</style>

sw600dp/styles.xml

 <style name="DialogControllerTypeGrid" parent="DialogControllerTypeGridBase">
        <item name="android:layout_width">450dp</item>
        <item name="android:numColumns">3</item>
 </style>

This way nothing gets duplicated and you dont use meaningles values like -1, -2 that dont work reliably across device based not just by me but also comments from others.

Renetik
  • 5,887
  • 1
  • 47
  • 66
0

You can create two layouts - default with android:layout_height="match_parent" in "layout" dir, and for tablet android:layout_height="320dp" in "layout-xlarge" dir

Marek Gocał
  • 555
  • 2
  • 12
  • I was trying to do the same thing, and this appears to be the best way to work things out. – James Feb 07 '12 at 12:47
  • 4
    this will be a pain, do duplicate the entire .xml just because of this single value. – Elye Jan 20 '16 at 00:20