TextView Avanzado en Android: Estilos, Tipografía y Color

TextView Avanzado en Android: Estilos, Tipografía y Color

Hola amigos 👋 Bienvenidos a un nuevo tutorial de Universo Android. Hoy aprenderemos a dominar el TextView en Android con técnicas avanzadas de estilos, tipografía, colores y formato de texto para crear interfaces profesionales y atractivas.

Al finalizar este tutorial tendrás una aplicación que incluirá:

  • TextView con estilos personalizados (negrita, cursiva, subrayado)
  • Tipografías personalizadas (fuentes custom)
  • Colores y gradientes
  • Texto con HTML y Spannable
  • Sombras y efectos visuales
  • Enlaces clicables
  • Texto multilínea con ellipsize

🟩 1. ¿Qué es TextView Avanzado?

TextView es el componente fundamental para mostrar texto en Android. El uso avanzado permite crear diseños profesionales con tipografías personalizadas, colores dinámicos, efectos visuales y formato de texto complejo.

🟩 2. Crear el Proyecto en Android Studio

Creamos un nuevo proyecto en Android Studio con Empty Activity.

🟩 3. Diseño XML con TextView Avanzado

Crea un archivo llamado:

📄 activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <!-- Título Principal -->
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Estilos de Texto"
            android:textSize="24sp"
            android:textStyle="bold"
            android:textColor="#2196F3"
            android:layout_marginBottom="16dp" />

        <!-- TextView con Negrita -->
        <TextView
            android:id="@+id/txtBold"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Texto en Negrita"
            android:textStyle="bold"
            android:textSize="18sp"
            android:layout_marginTop="8dp" />

        <!-- TextView con Cursiva -->
        <TextView
            android:id="@+id/txtItalic"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Texto en Cursiva"
            android:textStyle="italic"
            android:textSize="18sp"
            android:layout_marginTop="8dp" />

        <!-- TextView con Negrita y Cursiva -->
        <TextView
            android:id="@+id/txtBoldItalic"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Texto en Negrita y Cursiva"
            android:textStyle="bold|italic"
            android:textSize="18sp"
            android:layout_marginTop="8dp" />

        <!-- Separador -->
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#CCCCCC"
            android:layout_marginTop="16dp"
            android:layout_marginBottom="16dp" />

        <!-- Título: Colores -->
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Colores y Fondos"
            android:textSize="24sp"
            android:textStyle="bold"
            android:textColor="#4CAF50"
            android:layout_marginBottom="16dp" />

        <!-- TextView con Color Hexadecimal -->
        <TextView
            android:id="@+id/txtColorHex"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Texto con color hexadecimal"
            android:textColor="#FF5722"
            android:textSize="18sp"
            android:layout_marginTop="8dp" />

        <!-- TextView con Fondo de Color -->
        <TextView
            android:id="@+id/txtBackground"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Texto con fondo de color"
            android:textColor="#FFFFFF"
            android:background="#9C27B0"
            android:padding="12dp"
            android:textSize="18sp"
            android:layout_marginTop="8dp" />

        <!-- TextView con Fondo Redondeado -->
        <TextView
            android:id="@+id/txtRoundedBackground"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Texto con fondo redondeado"
            android:textColor="#FFFFFF"
            android:background="@drawable/rounded_background"
            android:padding="12dp"
            android:textSize="18sp"
            android:layout_marginTop="8dp" />

        <!-- Separador -->
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#CCCCCC"
            android:layout_marginTop="16dp"
            android:layout_marginBottom="16dp" />

        <!-- Título: Sombras -->
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Sombras y Efectos"
            android:textSize="24sp"
            android:textStyle="bold"
            android:textColor="#FF9800"
            android:layout_marginBottom="16dp" />

        <!-- TextView con Sombra -->
        <TextView
            android:id="@+id/txtShadow"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Texto con sombra"
            android:textSize="24sp"
            android:textStyle="bold"
            android:textColor="#2196F3"
            android:shadowColor="#000000"
            android:shadowDx="2"
            android:shadowDy="2"
            android:shadowRadius="4"
            android:layout_marginTop="8dp" />

        <!-- TextView con Sombra Suave -->
        <TextView
            android:id="@+id/txtSoftShadow"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Texto con sombra suave"
            android:textSize="24sp"
            android:textStyle="bold"
            android:textColor="#4CAF50"
            android:shadowColor="#00FF00"
            android:shadowDx="0"
            android:shadowDy="0"
            android:shadowRadius="10"
            android:layout_marginTop="8dp" />

        <!-- Separador -->
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#CCCCCC"
            android:layout_marginTop="16dp"
            android:layout_marginBottom="16dp" />

        <!-- Título: Espaciado -->
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Espaciado y Alineación"
            android:textSize="24sp"
            android:textStyle="bold"
            android:textColor="#E91E63"
            android:layout_marginBottom="16dp" />

        <!-- TextView con Letter Spacing -->
        <TextView
            android:id="@+id/txtLetterSpacing"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="ESPACIADO DE LETRAS"
            android:textSize="18sp"
            android:letterSpacing="0.3"
            android:layout_marginTop="8dp" />

        <!-- TextView con Line Spacing -->
        <TextView
            android:id="@+id/txtLineSpacing"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Este es un texto con\nespaciado entre líneas\npara mejorar la legibilidad"
            android:textSize="16sp"
            android:lineSpacingExtra="8dp"
            android:lineSpacingMultiplier="1.2"
            android:layout_marginTop="8dp" />

        <!-- Separador -->
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#CCCCCC"
            android:layout_marginTop="16dp"
            android:layout_marginBottom="16dp" />

        <!-- Título: Ellipsize -->
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Truncamiento de Texto"
            android:textSize="24sp"
            android:textStyle="bold"
            android:textColor="#00BCD4"
            android:layout_marginBottom="16dp" />

        <!-- TextView con Ellipsize End -->
        <TextView
            android:id="@+id/txtEllipsizeEnd"
            android:layout_width="200dp"
            android:layout_height="wrap_content"
            android:text="Este es un texto muy largo que será truncado al final"
            android:textSize="16sp"
            android:maxLines="1"
            android:ellipsize="end"
            android:layout_marginTop="8dp" />

        <!-- TextView con Ellipsize Middle -->
        <TextView
            android:id="@+id/txtEllipsizeMiddle"
            android:layout_width="200dp"
            android:layout_height="wrap_content"
            android:text="Este es un texto muy largo que será truncado en el medio"
            android:textSize="16sp"
            android:maxLines="1"
            android:ellipsize="middle"
            android:layout_marginTop="8dp" />

        <!-- TextView con Ellipsize Marquee -->
        <TextView
            android:id="@+id/txtEllipsizeMarquee"
            android:layout_width="200dp"
            android:layout_height="wrap_content"
            android:text="Este texto se desplazará como marquesina"
            android:textSize="16sp"
            android:maxLines="1"
            android:ellipsize="marquee"
            android:marqueeRepeatLimit="marquee_forever"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:scrollHorizontally="true"
            android:singleLine="true"
            android:layout_marginTop="8dp" />

        <!-- Separador -->
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#CCCCCC"
            android:layout_marginTop="16dp"
            android:layout_marginBottom="16dp" />

        <!-- Título: Texto Clickable -->
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Texto Interactivo"
            android:textSize="24sp"
            android:textStyle="bold"
            android:textColor="#673AB7"
            android:layout_marginBottom="16dp" />

        <!-- TextView con Link -->
        <TextView
            android:id="@+id/txtLink"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Visita nuestro sitio web"
            android:textSize="16sp"
            android:textColor="#2196F3"
            android:textStyle="bold"
            android:layout_marginTop="8dp" />

        <!-- TextView con HTML -->
        <TextView
            android:id="@+id/txtHtml"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="16sp"
            android:layout_marginTop="8dp" />

        <!-- TextView con Spannable -->
        <TextView
            android:id="@+id/txtSpannable"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="16sp"
            android:layout_marginTop="8dp" />

        <!-- Botones de Demostración -->
        <Button
            android:id="@+id/btnChangeStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Cambiar Estilo Dinámicamente"
            android:layout_marginTop="24dp" />

    </LinearLayout>

</ScrollView>

🟩 4. Crear Drawable para Fondo Redondeado

Crea un archivo res/drawable/rounded_background.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    
    <solid android:color="#FF5722" />
    
    <corners android:radius="16dp" />
    
    <padding
        android:left="16dp"
        android:top="8dp"
        android:right="16dp"
        android:bottom="8dp" />
    
</shape>

🟩 5. Crear Gradiente para TextView

Crea un archivo res/drawable/gradient_background.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    
    <gradient
        android:startColor="#2196F3"
        android:endColor="#E91E63"
        android:angle="45"
        android:type="linear" />
    
    <corners android:radius="8dp" />
    
</shape>

🟩 6. Lógica Java para TextView Avanzado

📄 MainActivity.java

import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Bundle;
import android.text.Html;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.text.style.BackgroundColorSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.RelativeSizeSpan;
import android.text.style.StyleSpan;
import android.text.style.UnderlineSpan;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    TextView txtLink, txtHtml, txtSpannable, txtBold;
    Button btnChangeStyle;
    boolean isStyleChanged = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Inicializar vistas
        txtLink = findViewById(R.id.txtLink);
        txtHtml = findViewById(R.id.txtHtml);
        txtSpannable = findViewById(R.id.txtSpannable);
        txtBold = findViewById(R.id.txtBold);
        btnChangeStyle = findViewById(R.id.btnChangeStyle);

        // Configurar marquesina
        TextView txtMarquee = findViewById(R.id.txtEllipsizeMarquee);
        txtMarquee.setSelected(true);

        // Configurar link clickable
        setupClickableLink();

        // Configurar HTML
        setupHtmlText();

        // Configurar Spannable
        setupSpannableText();

        // Botón para cambiar estilo
        btnChangeStyle.setOnClickListener(v -> changeStyleDynamically());
    }

    private void setupClickableLink() {
        txtLink.setOnClickListener(v -> 
            Toast.makeText(this, "Link clickeado!", Toast.LENGTH_SHORT).show()
        );
    }

    private void setupHtmlText() {
        String htmlText = "Este es un texto con <b>negrita</b>, " +
                "<i>cursiva</i>, <u>subrayado</u> y " +
                "<font color='#FF5722'>color</font>";
        
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
            txtHtml.setText(Html.fromHtml(htmlText, Html.FROM_HTML_MODE_LEGACY));
        } else {
            txtHtml.setText(Html.fromHtml(htmlText));
        }
    }

    private void setupSpannableText() {
        String text = "Texto con múltiples estilos aplicados";
        SpannableString spannableString = new SpannableString(text);

        // Aplicar negrita
        spannableString.setSpan(
            new StyleSpan(Typeface.BOLD),
            0, 5,
            Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
        );

        // Aplicar color
        spannableString.setSpan(
            new ForegroundColorSpan(Color.parseColor("#2196F3")),
            10, 19,
            Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
        );

        // Aplicar fondo
        spannableString.setSpan(
            new BackgroundColorSpan(Color.parseColor("#FFEB3B")),
            20, 27,
            Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
        );

        // Aplicar subrayado
        spannableString.setSpan(
            new UnderlineSpan(),
            28, 37,
            Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
        );

        // Aplicar tamaño relativo
        spannableString.setSpan(
            new RelativeSizeSpan(1.5f),
            28, 37,
            Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
        );

        txtSpannable.setText(spannableString);
    }

    private void changeStyleDynamically() {
        if (!isStyleChanged) {
            // Cambiar a estilo 1
            txtBold.setTextColor(Color.parseColor("#FF5722"));
            txtBold.setTextSize(24);
            txtBold.setTypeface(null, Typeface.BOLD_ITALIC);
            txtBold.setShadowLayer(5, 3, 3, Color.BLACK);
            btnChangeStyle.setText("Restaurar Estilo");
        } else {
            // Restaurar estilo original
            txtBold.setTextColor(Color.parseColor("#000000"));
            txtBold.setTextSize(18);
            txtBold.setTypeface(null, Typeface.BOLD);
            txtBold.setShadowLayer(0, 0, 0, Color.TRANSPARENT);
            btnChangeStyle.setText("Cambiar Estilo Dinámicamente");
        }
        isStyleChanged = !isStyleChanged;
    }
}

🟩 7. Agregar Fuentes Personalizadas

Paso 1: Crear carpeta de fuentes

Crea la carpeta res/font/ y agrega tus archivos de fuentes (.ttf o .otf)

Paso 2: Usar fuente en XML

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Texto con fuente personalizada"
    android:fontFamily="@font/mi_fuente_custom"
    android:textSize="20sp" />

Paso 3: Usar fuente en Java

Typeface customFont = ResourcesCompat.getFont(this, R.font.mi_fuente_custom);
textView.setTypeface(customFont);

🟩 8. Crear Estilos Reutilizables

Crea un archivo res/values/styles.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    
    <!-- Estilo para Títulos -->
    <style name="TitleTextStyle">
        <item name="android:textSize">24sp</item>
        <item name="android:textStyle">bold</item>
        <item name="android:textColor">#2196F3</item>
        <item name="android:layout_marginBottom">16dp</item>
    </style>
    
    <!-- Estilo para Subtítulos -->
    <style name="SubtitleTextStyle">
        <item name="android:textSize">18sp</item>
        <item name="android:textColor">#666666</item>
        <item name="android:layout_marginTop">8dp</item>
    </style>
    
    <!-- Estilo para Texto de Cuerpo -->
    <style name="BodyTextStyle">
        <item name="android:textSize">16sp</item>
        <item name="android:textColor">#333333</item>
        <item name="android:lineSpacingExtra">4dp</item>
    </style>
    
    <!-- Estilo para Enlaces -->
    <style name="LinkTextStyle">
        <item name="android:textSize">16sp</item>
        <item name="android:textColor">#2196F3</item>
        <item name="android:textStyle">bold</item>
    </style>
    
</resources>

Aplicar estilos en XML:

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Título Principal"
    style="@style/TitleTextStyle" />

🟩 9. Propiedades Avanzadas de TextView

PropiedadDescripción
android:textStyleEstilo del texto (normal, bold, italic)
android:textColorColor del texto
android:textSizeTamaño del texto
android:fontFamilyFamilia de fuente
android:letterSpacingEspaciado entre letras
android:lineSpacingExtraEspacio extra entre líneas
android:shadowColorColor de la sombra
android:shadowDxDesplazamiento X de la sombra
android:shadowDyDesplazamiento Y de la sombra
android:shadowRadiusRadio de difuminado de la sombra
android:ellipsizeModo de truncamiento (end, middle, marquee)
android:maxLinesNúmero máximo de líneas
android:textAllCapsConvertir a mayúsculas

🟩 10. Spannable Avanzado con Múltiples Efectos

private void advancedSpannableExample() {
    String text = "Android Development es increíble!";
    SpannableString spannable = new SpannableString(text);
    
    // Texto clickable
    ClickableSpan clickableSpan = new ClickableSpan() {
        @Override
        public void onClick(View widget) {
            Toast.makeText(MainActivity.this, "Texto clickeado!", Toast.LENGTH_SHORT).show();
        }
    };
    
    spannable.setSpan(clickableSpan, 0, 7, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    spannable.setSpan(new ForegroundColorSpan(Color.BLUE), 0, 7, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    spannable.setSpan(new UnderlineSpan(), 0, 7, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    
    textView.setText(spannable);
    textView.setMovementMethod(LinkMovementMethod.getInstance());
}

▶️ Cómo Ejecutar tu Aplicación

  1. Abre Android Studio
  2. Presiona Run para ejecutar el proyecto
  3. Si no tienes un emulador, crea uno desde AVD Manager
  4. Verás tus TextView con múltiples estilos, colores y efectos funcionando

🧪 Resultado Final

Tu aplicación mostrará:

  • TextView con diferentes estilos (negrita, cursiva, combinados)
  • Colores personalizados y fondos redondeados
  • Sombras y efectos visuales
  • Espaciado de letras y líneas
  • Truncamiento de texto con ellipsize
  • Texto con formato HTML y Spannable
  • Enlaces clickables e interactivos

📥 Descargar Proyecto de Ejemplo

Puedes descargar el proyecto completo desde el siguiente enlace:

👉 Descargar

🙌 Gracias por Visitar mi Blog

Si este tutorial te fue útil:

✔️ Compártelo
✔️ Déjame un comentario
✔️ Sígueme para más contenido sobre Android y programación

¡Estoy aquí para ayudarte!

❓ Preguntas Frecuentes (FAQ)

1. ¿Cómo puedo usar fuentes personalizadas en Android?
Coloca los archivos de fuentes (.ttf o .otf) en la carpeta res/font/ y úsalas con android:fontFamily="@font/tu_fuente" en XML o con Typeface en Java.

2. ¿Qué es Spannable y para qué sirve?
Spannable permite aplicar múltiples estilos a diferentes partes de un mismo texto, como colores, tamaños, negritas y fondos sin necesidad de usar múltiples TextView.

3. ¿Cómo puedo crear texto con gradiente?
Puedes usar un Shader con LinearGradient o TextPaint para aplicar gradientes a TextView, aunque requiere código Java personalizado.

4. ¿Es mejor usar HTML o Spannable para formatear texto?
Spannable ofrece mejor rendimiento y más control. HTML es más simple para formato básico pero tiene limitaciones en personalización.

No hay comentarios:

Publicar un comentario