Descripción general de los elementos de diseño

Prueba el método de Compose
Jetpack Compose es el kit de herramientas de IU recomendado para Android. Aprende a mostrar gráficos en Compose.

Cuando necesites mostrar imágenes estáticas en tu app, podrás usar la clase Drawable y sus subclases para dibujar formas y imágenes de contenedores. Un Drawable es una abstracción general para algo que se puede dibujar. Las diversas subclases ayudan con una imagen específica y puedes extenderlas para definir tus propios objetos de diseño que se comportan de maneras únicas.

Hay dos formas de definir un Drawable y crear una instancia de él, además de usar los constructores de clase:

  • Aumenta un recurso de imagen (un archivo de mapa de bits) guardado en tu proyecto.
  • Aumenta un recurso XML que define las propiedades del elemento de diseño.

Nota: Quizás prefieras usar un elemento de diseño vectorial, que define una imagen con un conjunto de puntos, líneas y curvas, junto con la información de color asociada. Permite elementos de diseño vectoriales para diferentes tamaños sin que se pierda la calidad. Para obtener más información, consulta la sección Vector descripción general de los elementos de diseño.

Cómo crear elementos de diseño a partir de recursos de imágenes

Puedes agregar gráficos a tu app haciendo referencia a un archivo de imagen de tu los recursos del proyecto. Los tipos de archivo admitidos son PNG (preferido), JPG (aceptable), y GIF (no recomendable). Íconos de apps, logotipos y otros gráficos, como los que se usan en los juegos, son adecuados para esta técnica.

Para usar un recurso de imagen, agrega tu archivo a res/drawable/ de tu proyecto. Cuando estés en tu proyecto, puedes hacer referencia a la imagen de tu código o tu diseño XML. De cualquier manera, se conoce como usar un resource ID, que es el nombre del archivo sin la extensión del tipo de archivo Para Por ejemplo, consulta my_image.png como my_image.

Nota: Los recursos de imagen que se colocan en res/drawable/ directorio puede optimizarse automáticamente con compresión de imágenes sin pérdida por parte de la herramienta aapt durante la compilación el proceso de administración de recursos. Por ejemplo, un archivo PNG con color verdadero que no requiera más de 256 colores se pueda convertir a un archivo PNG de 8 bits con una paleta de colores. Esto da como resultado una imagen de igual calidad, pero que requiere menos memoria. Como resultado, los objetos binarios de imagen que se coloca en este directorio puede cambiar durante el tiempo de compilación. Si planeas leer una como un flujo de bits para convertirla en un mapa de bits, coloca las imágenes en la res/raw/, en la que la herramienta aapt no modificarlos.

En el siguiente fragmento de código, se muestra cómo compilar un ImageView que use una imagen creada a partir de un recurso de elementos de diseño y la agrega al diseño:

Kotlin

private lateinit var constraintLayout: ConstraintLayout

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // Instantiate an ImageView and define its properties
    val i = ImageView(this).apply {
        setImageResource(R.drawable.my_image)
        contentDescription = resources.getString(R.string.my_image_desc)

        // set the ImageView bounds to match the Drawable's dimensions
        adjustViewBounds = true
        layoutParams = ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT)
    }

    // Create a ConstraintLayout in which to add the ImageView
    constraintLayout = ConstraintLayout(this).apply {

        // Add the ImageView to the layout.
        addView(i)
    }

    // Set the layout as the content view.
    setContentView(constraintLayout)
}

Java

ConstraintLayout constraintLayout;

protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  // Create a ConstraintLayout in which to add the ImageView
  constraintLayout = new ConstraintLayout(this);

  // Instantiate an ImageView and define its properties
  ImageView i = new ImageView(this);
  i.setImageResource(R.drawable.my_image);
  i.setContentDescription(getResources().getString(R.string.my_image_desc));

  // set the ImageView bounds to match the Drawable's dimensions
  i.setAdjustViewBounds(true);
  i.setLayoutParams(new ViewGroup.LayoutParams(
          ViewGroup.LayoutParams.WRAP_CONTENT,
          ViewGroup.LayoutParams.WRAP_CONTENT));

  // Add the ImageView to the layout and set the layout as the content view.
  constraintLayout.addView(i);
  setContentView(constraintLayout);
}

En otros casos, es posible que quieras controlar tu recurso de imagen como un objeto Drawable, como se muestra a continuación. ejemplo:

Kotlin

val myImage: Drawable = ResourcesCompat.getDrawable(context.resources, R.drawable.my_image, null)

Java

Resources res = context.getResources();
Drawable myImage = ResourcesCompat.getDrawable(res, R.drawable.my_image, null);

Advertencia: Cada recurso único en tu proyecto puede mantener un solo estado, sin importar cuántos objetos diferentes crear una instancia de él. Por ejemplo, si creas una instancia de dos objetos Drawable a partir del mismo recurso de imagen y cambiar una propiedad (como el alfa) de un objeto, también afecta el otro. Cuando se trata de varias instancias de un recurso de imagen, de transformar directamente el objeto Drawable, debes realizar un preadolescente animación.

En el siguiente fragmento de XML, se muestra cómo agregar un recurso de elemento de diseño a una ImageView en el diseño XML:

<ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/my_image"
        android:contentDescription="@string/my_image_desc" />

Para obtener más información sobre cómo usar los recursos del proyecto, consulta Recursos y elementos.

Nota: Cuando uses recursos de imagen como fuente de tus elementos de diseño, y asegúrate de que tengan el tamaño apropiado para distintas densidades de píxeles. Si el botón imágenes no son correctas, se ampliarán para ajustarse, lo que puede generar alteraciones en tus elementos de diseño. Para obtener más información, consulta Cómo brindar compatibilidad con diferentes densidades de píxeles.

Cómo crear elementos de diseño a partir de recursos de XML

Si hay un elemento Drawable que te gustaría crear, que inicialmente no depende de variables definidas por tu código o la interacción del usuario, definir Drawable en XML es una buena opción. Uniforme Si esperas que tu Drawable cambie sus propiedades durante la interacción del usuario con tu app, debes considerar definir el objeto en XML, ya que puedes modificar las propiedades después de se creó la instancia del objeto.

Después de definir tu Drawable en XML, guarda el archivo en el Directorio res/drawable/ de tu proyecto. En el siguiente ejemplo, se muestra el XML que define un TransitionDrawable recurso, que se hereda de Drawable:

<!-- res/drawable/expand_collapse.xml -->
<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/image_expand"/>
    <item android:drawable="@drawable/image_collapse"/>
</transition>

Luego, recupera y crea una instancia del objeto llamando Resources#getDrawable() y pasa el ID de recurso de tu archivo en formato XML. Cualquiera Subclase Drawable que admita el método inflate() se pueden definir en XML y se pueden crear instancias de tu app.

Cada clase de elemento de diseño compatible con el aumento XML usa atributos XML específicos que ayudan a definir las propiedades del objeto. El siguiente código crea una instancia de TransitionDrawable y lo establece como el contenido de un Objeto ImageView:

Kotlin

val transition= ResourcesCompat.getDrawable(
        context.resources,
        R.drawable.expand_collapse,
        null
) as TransitionDrawable

val image: ImageView = findViewById(R.id.toggle_image)
image.setImageDrawable(transition)

// Description of the initial state that the drawable represents.
image.contentDescription = resources.getString(R.string.collapsed)

// Then you can call the TransitionDrawable object's methods.
transition.startTransition(1000)

// After the transition is complete, change the image's content description
// to reflect the new state.

Java

Resources res = context.getResources();
TransitionDrawable transition =
    (TransitionDrawable) ResourcesCompat.getDrawable(res, R.drawable.expand_collapse, null);

ImageView image = (ImageView) findViewById(R.id.toggle_image);
image.setImageDrawable(transition);

// Description of the initial state that the drawable represents.
image.setContentDescription(getResources().getString(R.string.collapsed));

// Then you can call the TransitionDrawable object's methods.
transition.startTransition(1000);

// After the transition is complete, change the image's content description
// to reflect the new state.

Para obtener más información sobre los atributos XML admitidos, consulta las clases que se mencionaron anteriormente.

Elementos de diseño de forma

Un objeto ShapeDrawable puede ser una buena opción. cuando quieres dibujar dinámicamente un gráfico bidimensional. Puedes dibujar formas primitivas de manera programática en un objeto ShapeDrawable y aplicar los estilos que tu app necesita.

ShapeDrawable es una subclase de Drawable. Por este motivo, puedes usar una ShapeDrawable cuando se espera una Drawable. Para Por ejemplo, puedes usar un objeto ShapeDrawable para establecer el fondo. de una vista pasándola al método setBackgroundDrawable() de la vista. También puedes dibujar la forma como su tu propia vista personalizada y agregarla a un diseño en tu app.

Dado que ShapeDrawable tiene su propio método draw(), puedes crear un elemento subclase de View que dibuja el ShapeDrawable objeto durante el evento onDraw(), como se muestra en el siguiente ejemplo de código:

Kotlin

class CustomDrawableView(context: Context) : View(context) {
    private val drawable: ShapeDrawable = run {
        val x = 10
        val y = 10
        val width = 300
        val height = 50
        contentDescription = context.resources.getString(R.string.my_view_desc)

        ShapeDrawable(OvalShape()).apply {
            // If the color isn't set, the shape uses black as the default.
            paint.color = 0xff74AC23.toInt()
            // If the bounds aren't set, the shape can't be drawn.
            setBounds(x, y, x + width, y + height)
        }
    }

    override fun onDraw(canvas: Canvas) {
        drawable.draw(canvas)
    }
}

Java

public class CustomDrawableView extends View {
  private ShapeDrawable drawable;

  public CustomDrawableView(Context context) {
    super(context);

    int x = 10;
    int y = 10;
    int width = 300;
    int height = 50;
    setContentDescription(context.getResources().getString(
            R.string.my_view_desc));

    drawable = new ShapeDrawable(new OvalShape());
    // If the color isn't set, the shape uses black as the default.
    drawable.getPaint().setColor(0xff74AC23);
    // If the bounds aren't set, the shape can't be drawn.
    drawable.setBounds(x, y, x + width, y + height);
  }

  protected void onDraw(Canvas canvas) {
    drawable.draw(canvas);
  }
}

Puedes usar la clase CustomDrawableView en la muestra de código. arriba, como usarías cualquier otra vista personalizada. Por ejemplo, puedes de forma programática a una actividad de tu app, como se muestra en el siguiente ejemplo:

Kotlin

private lateinit var customDrawableView: CustomDrawableView

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    customDrawableView = CustomDrawableView(this)

    setContentView(customDrawableView)
}

Java

CustomDrawableView customDrawableView;

protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  customDrawableView = new CustomDrawableView(this);

  setContentView(customDrawableView);
}

Si deseas usar la vista personalizada en el diseño XML, La clase CustomDrawableView debe anular el constructor View(Context, AttributeSet), al que se llama cuando la clase se infle a partir de XML. En el siguiente ejemplo, se muestra cómo declarar el CustomDrawableView en el diseño XML:

<com.example.shapedrawable.CustomDrawableView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        />

La clase ShapeDrawable, como muchas otras de elementos de diseño en el paquete android.graphics.drawable, te permite definir varias propiedades del objeto mediante métodos públicos. Algunos ejemplos que puede ajustar incluyen la transparencia alfa, el filtro de color la interpolación, la opacidad y el color.

También puedes definir formas básicas de elementos de diseño con recursos XML. Para ver más consulta Elemento de diseño de forma en Tipos de recursos de elementos de diseño.

Elementos de diseño de NinePatch

Un gráfico NinePatchDrawable es un imagen de mapa de bits extensible que puedes usar como fondo de una vista. En Android cambia automáticamente el tamaño del gráfico para que se ajuste al contenido de la vista. Los ejemplo de uso de una imagen de NinePatch es el fondo que usa Android estándar botones: los botones deben estirarse para adaptarse a cadenas de diferentes longitudes. R El gráfico de NinePatch es una imagen PNG estándar que incluye un borde adicional de 1 píxel. Se debe guardar con la extensión 9.png en el Directorio res/drawable/ de tu proyecto.

Usa el borde para definir las áreas extensibles y estáticas de la imagen. Para indicar una sección extensible, dibuja uno (o más) de 1 píxel de ancho. líneas negras en la parte izquierda y superior del borde (los otros píxeles del borde) debe ser completamente transparente o blanco). Puedes tener tantas secciones estirables como quieras. El tamaño relativo de las secciones extensibles permanece igual, de la sección más grande siempre sigue siendo la más grande.

También puedes definir una sección opcional de elementos de diseño de la imagen (efectivamente, las líneas de relleno) dibujando una línea a la derecha y otra en la parte inferior. Si un El objeto View establece el gráfico de NinePatch como fondo. y luego especifica el texto de la vista, se estira para que todo el texto Ocupa solo el área designada por la línea derecha y la línea inferior (si se incluyen). Si no se incluyen las líneas de relleno, Android usa las líneas izquierda y superior para definir esta área del elemento de diseño.

Para aclarar la diferencia entre las líneas, la izquierda y la superior definen qué píxeles de la imagen pueden replicarse para estirar la imagen. Las líneas inferior y derecha definen el área relativa dentro de la imagen que puede ocupar el contenido de la vista.

En la figura 1, se muestra un ejemplo de un gráfico de NinePatch que se usa para definir un botón:

Imagen de un área extensible
y un cuadro de relleno

Figura 1: Ejemplo de un gráfico de NinePatch que define un botón

Este gráfico de NinePatch define un área extensible con los extremos izquierdo y superior líneas y el área del elemento de diseño con las líneas inferior y derecha. En la imagen superior, las líneas grises punteadas identifican las regiones de la imagen que se replican para estirar la imagen. El rectángulo rosado en la imagen inferior identifica la región en la que está permitido el contenido de la vista. Si el contenido no esta región, entonces la imagen se estira para que quepa.

La herramienta Draw 9-patch ofrece una muy útil para crear imágenes de NinePatch con un gráfico WYSIWYG Editor. Incluso muestra advertencias si la región que definiste para la capa el área corre el riesgo de producir artefactos de dibujo como resultado de la la replicación.

En el siguiente ejemplo de XML de diseño, se muestra cómo agregar un gráfico de NinePatch a un par de botones. La imagen de NinePatch se guarda en res/drawable/my_button_background.9.png

<Button android:id="@+id/tiny"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerInParent="true"
        android:text="Tiny"
        android:textSize="8sp"
        android:background="@drawable/my_button_background"/>

<Button android:id="@+id/big"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerInParent="true"
        android:text="Biiiiiiig text!"
        android:textSize="30sp"
        android:background="@drawable/my_button_background"/>

Ten en cuenta que layout_width y layout_height se establecieron en wrap_content para que el botón se ajuste perfectamente alrededor del texto.

En la figura 2, se muestran los dos botones renderizados a partir de la imagen XML y NinePatch como se muestra arriba. Observa cómo el ancho y la altura del botón varían según el texto. y la imagen de fondo se estirará para adaptarse a ella.

Imagen de una imagen diminuta
botones de tamaño normal

Figura 2: Botones renderizados con un XML recurso y un gráfico de NinePatch

Elementos de diseño personalizados

Cuando quieras crear algunos dibujos personalizados, podrás hacerlo si extiendes la clase Drawable (o cualquiera de sus subclases).

El método más importante de implementación es draw(Canvas). ya que proporciona el objeto Canvas que debes usar para proporcionar tus instrucciones de dibujo.

En el siguiente código, se muestra una subclase simple de Drawable. que dibuja un círculo:

Kotlin

class MyDrawable : Drawable() {
    private val redPaint: Paint = Paint().apply { setARGB(255, 255, 0, 0) }

    override fun draw(canvas: Canvas) {
        // Get the drawable's bounds
        val width: Int = bounds.width()
        val height: Int = bounds.height()
        val radius: Float = Math.min(width, height).toFloat() / 2f

        // Draw a red circle in the center
        canvas.drawCircle((width / 2).toFloat(), (height / 2).toFloat(), radius, redPaint)
    }

    override fun setAlpha(alpha: Int) {
        // This method is required
    }

    override fun setColorFilter(colorFilter: ColorFilter?) {
        // This method is required
    }

    override fun getOpacity(): Int =
        // Must be PixelFormat.UNKNOWN, TRANSLUCENT, TRANSPARENT, or OPAQUE
        PixelFormat.OPAQUE
}

Java

public class MyDrawable extends Drawable {
    private final Paint redPaint;

    public MyDrawable() {
        // Set up color and text size
        redPaint = new Paint();
        redPaint.setARGB(255, 255, 0, 0);
    }

    @Override
    public void draw(Canvas canvas) {
        // Get the drawable's bounds
        int width = getBounds().width();
        int height = getBounds().height();
        float radius = Math.min(width, height) / 2;

        // Draw a red circle in the center
        canvas.drawCircle(width/2, height/2, radius, redPaint);
    }

    @Override
    public void setAlpha(int alpha) {
        // This method is required
    }

    @Override
    public void setColorFilter(ColorFilter colorFilter) {
        // This method is required
    }

    @Override
    public int getOpacity() {
        // Must be PixelFormat.UNKNOWN, TRANSLUCENT, TRANSPARENT, or OPAQUE
        return PixelFormat.OPAQUE;
    }
}

Luego, puedes agregar tu elemento de diseño donde quieras, por ejemplo, en un ImageView, como se muestra aquí:

Kotlin

val myDrawing = MyDrawable()
val image: ImageView = findViewById(R.id.imageView)
image.setImageDrawable(myDrawing)
image.contentDescription = resources.getString(R.string.my_image_desc)

Java

MyDrawable mydrawing = new MyDrawable();
ImageView image = findViewById(R.id.imageView);
image.setImageDrawable(mydrawing);
image.setContentDescription(getResources().getString(R.string.my_image_desc));

En Android 7.0 (nivel de API 24) y versiones posteriores, también puedes definir instancias de tu elemento de diseño personalizado. con XML de las siguientes maneras:

  • Puedes usar el nombre completo de la clase como el nombre del elemento XML. Para este enfoque, la arquitectura drawable debe ser una clase pública de nivel superior:
    <com.myapp.MyDrawable xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="#ffff0000" />
    
  • Usa drawable como el nombre de la etiqueta XML y especifica la clase completamente calificada. del atributo de clase. Este enfoque se puede usar tanto para las clases públicas de nivel superior como para Clases internas estáticas públicas:
    <drawable xmlns:android="http://schemas.android.com/apk/res/android"
        class="com.myapp.MyTopLevelClass$MyDrawable"
        android:color="#ffff0000" />
    

Cómo agregar un tono a los elementos de diseño

Con Android 5.0 (nivel de API 21) y versiones posteriores, puedes cambiar el matiz de los mapas de bits y nueve parches definidos como alfa. Puedes cambiar el tono con recursos de color o atributos de tema que se resuelven a color. recursos (por ejemplo, ?android:attr/colorPrimary). Por lo general, tú creas estos recursos una sola vez y colorearlas automáticamente para que coincidan con tu tema.

Puedes aplicar un tono a BitmapDrawable, NinePatchDrawable o VectorDrawable objetos con el método setTint(). Puedes también puedes establecer el color y el modo del tono en tus diseños con android:tint y android:tintMode.

Cómo extraer colores destacados de una imagen

La biblioteca de compatibilidad de Android incluye la clase Palette, que te permite extraer colores destacados de una imagen. Puedes cargar tus elementos de diseño como un Bitmap y pasarlo a Palette para acceder a sus colores. Para obtener más información, consulta Cómo seleccionar colores con la API de Palette.