Search code examples
javaandroidresolution

Using resolution independant fonts within an android layout


Background

I'm creating a layout for an android application and have until now been using font sizes expressed in sp (or dp) in order that they scale correctly for different devices. However the result has been different to what I was hoping. The result has been that text is the same physical size (in terms of inches) on all devices whereas what I'd like is for it to occupy the same proportion of the screen.

At present my menu buttons look somewhat small on tablets but ludicrously large on phones (see screenshots; although it doesn't do justice to how bad the phone version looks).

Using px actually gives me the results I want for these particular devices but that is because they have similar resolutions (but very different pixel densities). If I used pixels based upon how I want it to look on these two devices (both approximately 1,200 x 700) and the Galaxy S10 came out that was the same physical size as the galaxy S3 but had a resolution of 10,000 x 7,000 then my buttons would look ridiculously small.

Question

How can I set a font size (or any size) that is resolution independent (not density independent)?

Galaxy S3 - large phone

enter image description here

Tab 3 - medium sided tablet

enter image description here

Current layout

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:gravity="center"
    android:background="@drawable/menubackground"
    >
    
   <LinearLayout 
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:orientation="vertical" 
        android:layout_gravity="center"
        android:gravity="center"
     >
         <Button
         android:layout_height="wrap_content"
         android:layout_width="fill_parent"
         android:text="@string/singleplayer"
         android:layout_marginTop="50dp"
         android:layout_marginBottom="50dp"
         android:textSize="50sp"
         android:onClick="singleplayer" 

         />
          
         <Button
         android:layout_height="wrap_content"
         android:layout_width="fill_parent"
         android:text="@string/twoplayer"
         android:layout_marginTop="50dp"
         android:layout_marginBottom="50dp"
         android:textSize="50sp"
         android:onClick="twoplayer" 
         /> 
         
         <Button
         android:layout_height="wrap_content"
         android:layout_width="fill_parent"
         android:text="@string/campaign"
         android:layout_marginTop="50dp"
         android:layout_marginBottom="50dp"
         android:textSize="50sp"
         android:onClick="campaign" 
         />
         
         <Button
         android:layout_height="wrap_content"
         android:layout_width="fill_parent"
         android:text="@string/ai_vs_ai"
         android:layout_marginTop="50dp"
         android:layout_marginBottom="50dp"
         android:textSize="50sp"
         android:onClick="aiVsAI" 
         />
    </LinearLayout>
      

</LinearLayout>

Solution

  • First, as you state, dp (density independent pixels) are supposed to look about the same "physical" size in all devices, no matter the display density, while sp (scaled pixels) are supposed to scale based on user preferences. So they are not suitable for what you're attempting to do.

    If you don't want different layouts, but only different font sizes, you can use references to resources for these attributes. For example, you can create alternative xml files for values and values-large:

    In values:

    <dimen name="mainMenuOption">50sp</dimen>
    

    In values-large:

    <dimen name="mainMenuOption">80sp</dimen>
    

    And then, inside your layout, use:

    <Button
        android:layout_height="wrap_content"
        android:textSize="@dimen/mainMenuOption"
        ...
    

    Most (though not all) attributes can use references to resources.

    Of course, this does not achieve "resolution independence", but it allows customizing just "small parts" instead of whole layouts depending on device characteristics.