Освой Android играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

CardView (Карточка)

Создадим карточку программно
MaterialCardView
    Свечение (API 28)

Компонент CardView появился в Android Lollipop (API 21), но благодаря библиотеке совместимости доступен и для старых устройств. По сути является дальнейшим развитием FrameLayout и позволяет создавать красивую карточку с тенью и закруглёнными углами, который служит контейнером для других компонентов.

Доступен на панели инструментов в разделе Containers. Сейчас компонент входит в состав AndroidX. Если добавлять в студии из панели Palette в обычных проектах из шаблонов, то используются два стандартных пакета. Если вы используете собственный проект со своими зависимостями, то добавьте отдельную библиотеку.


implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.core:core-ktx:1.3.2'

// если добавлять отдельно в каких-то проектах
implementation "androidx.cardview:cardview:1.0.0"

Создадим разметку и добавим в карточку текстовое поле.


<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/rootLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <androidx.cardview.widget.CardView
        android:id="@+id/card_view"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_gravity="center"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        app:cardCornerRadius="4dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <TextView
            android:id="@+id/info_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center_vertical|center_horizontal|top"
            android:text="Карточка на кота Василия"
            android:textSize="36sp" />
    </androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>

Это простейший вариант для знакомства.

CardView

Стилизация

Добавим стили для карточки в styles.xml:


<style name="MyCardViewStyle" parent="Theme.AppCompat.Light">  
    <item name="cardCornerRadius">2dp</item>
    <item name="cardElevation">2dp</item>
    <item name="cardMaxElevation">4dp</item>
    <item name="contentPaddingBottom">24dp</item>
    <item name="contentPaddingTop">24dp</item>
    <item name="contentPaddingLeft">16dp</item>
    <item name="contentPaddingRight">16dp</item>
    <item name="cardBackgroundColor">@color/indigo</item>
</style>  

Подключаем через атрибут android:style.

В последнее время карточки часто используют в RecyclerView.

Создадим карточку программно

Пример программного создания карточки. Макет для экрана активности.


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Create CardView" />

</LinearLayout>

По щелчку кнопки создаём карточку. Второй щелчок создаст вторую карточку и т.д. Также добавим обработку щелчка на самой карточке.


// Если этот код работает, его написал Александр Климов,
// а если нет, то не знаю, кто его писал.

package ru.alexanderklimov.card

import android.graphics.Color
import android.os.Bundle
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.cardview.widget.CardView
import kotlinx.android.synthetic.main.activity_main.*


class MainActivity : AppCompatActivity() {

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

        setContentView(R.layout.activity_main)

        button.setOnClickListener {
            // Initialize a new CardView instance
            val cardView = CardView(this)

            // Initialize a new LayoutParams instance, CardView width and height
            val layoutParams = LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.MATCH_PARENT, // CardView width
                    LinearLayout.LayoutParams.WRAP_CONTENT // CardView height
            )

            // Set margins for card view
            layoutParams.setMargins(20, 20, 20, 20)

            // Set the card view layout params
            cardView.layoutParams = layoutParams

            // Set the card view corner radius
            cardView.radius = 16F

            // Set the card view content padding
            cardView.setContentPadding(25,25,25,25)

            // Set the card view background color
            cardView.setCardBackgroundColor(Color.LTGRAY)

            // Set card view elevation
            cardView.cardElevation = 8F

            // Set card view maximum elevation
            cardView.maxCardElevation = 12F

            // Set a click listener for card view
            cardView.setOnClickListener{
                Toast.makeText(
                        applicationContext,
                        "Card clicked.",
                        Toast.LENGTH_SHORT).show()
            }

            // Add an ImageView to the CardView
            cardView.addView(generateImageView())

            // Finally, add the CardView in root layout
            root_layout.addView(cardView)
        }
    }

    private fun generateImageView(): ImageView {
        val imageView = ImageView(this)
        val params = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, 350)
        imageView.layoutParams = params
        imageView.setImageResource(R.drawable.hungrycat)
        imageView.scaleType = ImageView.ScaleType.CENTER_CROP
        return imageView
    }
}

CardView

MaterialCardView

В версии Design Support Library 28.0.0 появился компонент MaterialCardView, который может заменить CardView. Он изначально спроектирован для использования в Material Design. Сейчас нужно использовать com.google.android.material, не забудьте поправить в новых проектах.


implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.google.android.material:material:1.2.0-alpha05'

Не забываем установить правильную тему из семейства MaterialComponents, иначе приложение может закрываться с ошибкой.


<style name="AppTheme" parent="Theme.MaterialComponents.Light.DarkActionBar">

Для сравнения добавим два компонента.


<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/rootLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.cardview.widget.CardView
        android:id="@+id/standartd_card"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        app:cardCornerRadius="4dp"
        app:contentPadding="10dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <TextView
            android:id="@+id/info_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center_vertical|center_horizontal|top"
            android:text="Стандартная\\nкарточка CardView"
            android:textSize="36sp" />
    </androidx.cardview.widget.CardView>

    <com.google.android.material.card.MaterialCardView
        android:id="@+id/material_card"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="24dp"
        android:layout_marginEnd="8dp"
        app:cardCornerRadius="3dp"
        app:cardElevation="5dp"
        app:cardMaxElevation="8dp"
        app:cardPreventCornerOverlap="true"
        app:cardUseCompatPadding="false"
        app:contentPadding="10dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/standartd_card">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="Карточка \nMaterialCardView"
            android:textSize="36sp" />
    </com.google.android.material.card.MaterialCardView>
</androidx.constraintlayout.widget.ConstraintLayout>

MaterialCardView

У MaterialCardView есть атрибуты обводки (и многие другие).

  • app:strokeColor - цвет обводки
  • app:strokeWidth - ширина обводки

MaterialCardView

Карточка может реагировать на нажатия, превращаясь в подобие кнопки. Сначала добавим несколько дополнительных атрибутов.


android:clickable="true"
android:focusable="true"
android:checkable="true"

Напишем код для длительного нажатия на карточку.


material_card.setOnLongClickListener {
    material_card.isChecked = !material_card.isChecked
    true
}

В выбранном состоянии карточка меняет свой цвет и в углу появляется значок флажка.

MaterialCardView

Значок флажка можно изменить при помощи атрибута app:checkedIcon.

MaterialCardView

Многие XML-атрибуты можно менять программно через соответствующие функции. Если взять атрибут app:cardCornerRadius, то там мы обычно используем dp вместо px, однако в коде принято использовать пиксели в качестве единицы измерения. Поэтому удобнее создать функцию-расширение, чтобы было удобнее работать с dp.


fun Int.toDp(context: Context): Int = TypedValue.applyDimension(
    TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), context.resources.displayMetrics
).toInt()

material_card.apply {
    // border color
    strokeColor = Color.parseColor("#007FFF")
    // border width in dp
    strokeWidth = 4.toDp(context)
    radius = 12.toDp(context).toFloat()
}

Свечение (API 28)

В Android P (API 28) у карточки появились новые атрибуты для создания эффекта свечения.


<com.google.android.material.card.MaterialCardView
    android:id="@+id/material_card"
    ..
    android:outlineAmbientShadowColor="#E30022"
    android:outlineSpotShadowColor="#E30022"
    app:cardElevation="20dp"
    ...">

Программный способ.


material_card.apply {
    // API 28
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        outlineAmbientShadowColor = Color.GREEN
        outlineSpotShadowColor = Color.GREEN
    }
}

Дополнительные материалы

Реклама