Tip Android #14: estilos para SeekBar

  • 17/01/2013 (Primera publicación)
  • 02/08/2015: Actualizado a Lollipop
  • android tip

    En el tip anterior se mostró cómo utilizar una SeekBar e implementar su listener, en éste vamos a ver cómo personalizar su aspecto mediante drawables y hacer que el widget «encaje» en el diseño global de nuestra app independientemente de la versión de Android que se utilice. En primer lugar, debemos tener en cuenta que toda SeekBar consta de dos elementos a los que aplicamos estilos de forma independiente:

    • Thumb: es el «botón» o imagen similar que arrastramos y que marca el punto (valor) de la SeekBar que está seleccionado.
    • Progress: es la barra por la que desplazamos el thumb. Este elemento tiene a su vez tres estilos:
      • background: es la zona de la barra a la derecha del thumb, esto es, el rango de valores siguiente al seleccionado.
      • progress: es la zona de la barra a la izquierda del thumb, esto es, el rango de los valores inferiores al seleccionado.
      • secondary progress: es la zona de la barra que queda a la izquierda del valor establecido como «android:secondaryProgress» y que no está ocupada por el estilo progress. Obviamente si no se define este atributo de la SeekBar el estilo nunca se aplicará. La principal utilidad de este estilo es indicar al usuario un valor por defecto o recomendado.

    Vamos a partir del proyecto de ejemplo del tip anterior, y definimos en el layout los drawables con los estilos a aplicar (también se podría definir un estilo para la SeekBar y dentro de ese estilo hacer referencia a los drawables). Tal y como hemos visto, vamos a darle estilo a los dos elementos (también definimos el atributo android:secondaryProgress para probar este estilo):

    <?xml version="1.0" encoding="utf-8"?>
    
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" 
        android:background="@android:color/black">
    
        <SeekBar
            android:id="@+id/seekBar"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true" 
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp" 
            android:paddingRight="20dp"
            android:paddingLeft="20dp"
            android:secondaryProgress="40"
            android:thumb="@drawable/thumb_seekbar"
            android:progressDrawable="@drawable/progress_seekbar"/>
    
        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_above="@+id/seekBar"
            android:layout_centerHorizontal="true"
            android:textAppearance="?android:attr/textAppearanceMedium" />
    
    </RelativeLayout>
    
    

    El drawable para el thumb es el siguiente:

    <?xml version="1.0" encoding="utf-8"?>
     
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
    
        <!-- presionado -->
        <item android:state_pressed="true"
              android:state_window_focused="true"
              android:drawable="@drawable/seek_thumb_pressed" />
    	
    	<!-- con foco -->
        <item android:state_focused="true"
              android:state_window_focused="true"
              android:drawable="@drawable/seek_thumb_selected" />
    	
    	<!-- seleccionado -->
        <item android:state_selected="true"
              android:state_window_focused="true"
              android:drawable="@drawable/seek_thumb_selected" />
    
        <!-- estado "normal" -->
        <item android:drawable="@drawable/seek_thumb_normal" />
    
    </selector>
    

    Las imágenes a las que hacemos referencia deberán ubicarse, en función de su resolución, en /res/drawable-ldpi, /res/drawable-mdpi, etc. Como punto de partida o referencia, echemos un vistazo a las imágenes de la API de Android 2:

    densidad resolución seek_thumb_normal.png seek_thumb_pressed.png seek_thumb_selected.png
    ldpi 24×22
    mdpi 32×29
    hdpi 48×44
    xdpi 64×59

    Veamos ahora el drawable para la barra y sus tres elementos. El ejemplo es sencillo y utiliza colores sólidos y bordes curvos, pero se podrían usar gradientes o incluso imágenes 9-patch.

    <?xml version="1.0" encoding="utf-8"?>
    
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    
        <item android:id="@android:id/background">
            <shape>
                <corners android:radius="5dip" />
    
                <solid android:color="@color/seekbarfree" />
            </shape>
        </item>
        <item android:id="@android:id/secondaryProgress">
            <clip> 
                <shape>
                    <corners android:radius="5dip" />
    
                    <solid android:color="@android:color/white" />
                </shape>
            </clip>
        </item>
        <item android:id="@android:id/progress">
            <clip>
                <shape>
                    <corners android:radius="5dip" />
    
                    <solid android:color="@color/seekbar" />
                </shape>
            </clip>
        </item>
    
    </layer-list>
    

    Como buena práctica, los colores los definimos en el fichero /res/values/colors.xml:

    <?xml version="1.0" encoding="utf-8"?>
    
    <resources>
            
        <color name="seekbar">#ababab</color>
        <color name="seekbarfree">#4a4a4a</color>    
    
    </resources>
    

    Lollipop

    Si ejecutamos el ejemplo en Lollipop, el thumb muestra un borde negro:

    seekbar lollipop splittrack

    La solución consiste en hacer que nuestra aplicación tenga por target la API 21+ y definir la propiedad splitTrack en la Seekbar como false:

       android:secondaryProgress="40"
            android:thumb="@drawable/thumb_seekbar"
            android:progressDrawable="@drawable/progress_seekbar"
            android:splitTrack="false" />
    

    El resultado final en Jelly Bean



    El proyecto completo para Eclipse ADT se encuentra en Github. Para más información sobre cómo utilizar GitHub, consultar este artículo.

    << TIPS ANDROID

    Deja una respuesta

    Introduce tus datos o haz clic en un icono para iniciar sesión:

    Logo de WordPress.com

    Estás comentando usando tu cuenta de WordPress.com. Salir /  Cambiar )

    Foto de Facebook

    Estás comentando usando tu cuenta de Facebook. Salir /  Cambiar )

    Conectando a %s

    Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.