Освой Android играючи
/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000
Создадим карточку программно
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>
Это простейший вариант для знакомства.

Добавим стили для карточки в 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
}
}

В версии 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 есть атрибуты обводки (и многие другие).

Карточка может реагировать на нажатия, превращаясь в подобие кнопки. Сначала добавим несколько дополнительных атрибутов.
android:clickable="true"
android:focusable="true"
android:checkable="true"
Напишем код для длительного нажатия на карточку.
material_card.setOnLongClickListener {
material_card.isChecked = !material_card.isChecked
true
}
В выбранном состоянии карточка меняет свой цвет и в углу появляется значок флажка.

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

Многие 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()
}
В 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
}
}