tags:

views:

252

answers:

4

I've got a desire for a one-pixel divider line, just for looks. I thought I could accomplish this using a View of height 1px, with a defined background. However, I'm getting some very odd behavior on different devices - sometimes the 1px ends up as 2px.

Take this sample layout for example:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <View android:layout_width="fill_parent" android:layout_height="1px"
        android:background="@android:color/white" android:layout_marginBottom="4dp" />
    <View android:layout_width="fill_parent" android:layout_height="1px"
        android:background="@android:color/white" android:layout_marginBottom="4dp" />
    <View android:layout_width="fill_parent" android:layout_height="1px"
        android:background="@android:color/white" android:layout_marginBottom="4dp" />
    <View android:layout_width="fill_parent" android:layout_height="1px"
        android:background="@android:color/white" android:layout_marginBottom="4dp" />
    <View android:layout_width="fill_parent" android:layout_height="1px"
        android:background="@android:color/white" android:layout_marginBottom="4dp" />
    <View android:layout_width="fill_parent" android:layout_height="1px"
        android:background="@android:color/white" android:layout_marginBottom="4dp" />
    <View android:layout_width="fill_parent" android:layout_height="1px"
        android:background="@android:color/white" android:layout_marginBottom="4dp" />
</LinearLayout>

When run on my G1, this comes out fine. But on the Nexus One, it alternates between 1px lines and 2px lines.

Does anyone know where this is going awry? Why does Android sometimes make 1px into 2px?

Edit: To make this absolutely clear, I do not care about solving my example in particular; what I care about is being able to say "this View shall be 1px high", in any circumstance, not just this example.

+1  A: 

I would imagine that this is occurring where the line is on the edge between pixels ; is this occuring because you are mixing dp (density-independant) pixel measurements with absolutes? If the devices have different dp / pixel ratios your margins (defined in dps) could be placing your separators on the edge between pixels.

Try changing your margins to 4px instead of 4dp.

Adrian
Changing the margins to 4px instead of 4dp doesn't help (still get a mixture of 1px and 2px lines), though you may be on to something.
Daniel Lew
A: 

I know this is not the question, but if you are using a ListView, you have some properties for dividers:

android:divider="" /*color, drawable, etc*/
android:dividerHeight="1dip"

Plus you really shouldn't use Pixels but independant density measurement..

Rorist
You're right, this doesn't answer the question at all because I'm not asking about this for ListViews. :P I may ultimately use more of the implementation ListView uses for its dividers though, since they seem to remain consistent despite location.
Daniel Lew
A: 

As you've already surmised, this is an auto-scaling issue. Android is recalculating things on the fly, and the coordinates are not mapping cleanly to the new grid.

To make it align properly, assign "3dp" or "5dp" to the layout_marginBottom. Basically, it must be an odd number, so that if you add it to the layout_height, its sum results in an even number.

Here is one solution that solves this very issue on my 2.1 Droid:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="fill_parent"
    android:layout_height="fill_parent">
<View android:layout_width="fill_parent" android:layout_height="1dp"
    android:background="@android:color/white" android:layout_marginBottom="3dp" />
<View android:layout_width="fill_parent" android:layout_height="1dp"
    android:background="@android:color/white" android:layout_marginBottom="3dp" />
<View android:layout_width="fill_parent" android:layout_height="1dp"
    android:background="@android:color/white" android:layout_marginBottom="3dp" />
<View android:layout_width="fill_parent" android:layout_height="1dp"
    android:background="@android:color/white" android:layout_marginBottom="3dp" />
<View android:layout_width="fill_parent" android:layout_height="1dp"
    android:background="@android:color/white" android:layout_marginBottom="3dp" />
<View android:layout_width="fill_parent" android:layout_height="1dp"
    android:background="@android:color/white" android:layout_marginBottom="3dp" />
<View android:layout_width="fill_parent" android:layout_height="1dp"
    android:background="@android:color/white" android:layout_marginBottom="3dp" />
</LinearLayout>

And should you add anything else between the lines, make sure that the distances, between the edges of each line, always remain odd.

And yes, Adrian is right. Even if it doesn't change anything in this particular case, it's a good habit to have -- to always be using "dp" or "dip", density-independent pixels instead of absolute pixels ("px").

Stephan Branczyk
The problem is that my example is *not* what I actually want to do. The actual circumstance for this is rather particular; I'm not trying to solve my particular example, I'm trying to solve all cases where 1px is not coming out as 1px.
Daniel Lew
Hmmm. The google people have said that their Drawables auto-scaling doesn't work very well where it comes to 1, 2, or 3 pixels. Now of course, you could turn off auto-scaling altogether, or at least auto-scale only on a proportional subset of the screen, and render only on that subset (a black border would appear where the screen had not rendered, but your app would still work and the proportions would be the same). A third possibility I suppose, would be to use the image of "one pixel" to make each line, and use a different image for the ldpi, mdpi, and hdpi, folders of the drawables.
Stephan Branczyk
That being said, I haven't tried that third possibility, so I'm not even sure if that will work. Sorry, I can't be more helpful.
Stephan Branczyk
Oh! A fourth possibility (again untested) would to use a nine patch image. At least with a nine patch, you could tell it which part would remain unstretchable (the pixel's width), and which parts could be stretched (the margins).http://developer.android.com/guide/developing/tools/draw9patch.html
Stephan Branczyk
+3  A: 

Are you building against SDK 1.5, or setting android:anyDensity="false"? If your app does not say it supports densities, then Android will run in compatibility mode where it makes the screen look like an mdpi screen, scaling ALL coordinates and drawing to match the real screen density. Running in an hdpi screen like Droid, this is a 1.5x scaling, so every other "pixel" will be mapped to two pixels on the screen.

Apps today should be written to support different screens, in which case the px and dp units will behave as desired on all screens.

hackbod
Wow, that did it for me! I change my min SDK from 3 to 4 and it fixed my problem. I was seeing this symptom with my list view dividers. Your my hero! :)
hambonious
If I want an app that runs with android:minSdkVersion="3" what can I do to not run in compatibility mode?
Janusz
android:targetSdkVersion="<somethinglarger>"
hackbod