Android Graphics

автор:

Татьяна Распутина

Ресурсы

Ресурсы

Какие бывают типы ресурсов?

  • Изображения
  • Строковые константы
  • Цвета
  • Размеры
  • Анимации
  • Стили
  • Файлы разметки
  • Дополнительные типы ресурсов: Integer, Bool, Typed Array

Зачем экспортировать ресурсы?

  • Позволяет поддерживать, обновлять и редактировать ресурсы независимо от исходного кода
  • Позволяет предоставлять альтернативные ресурсы для разных конфигураций устройств
  • Позволяет переиспользовать ресурсы по ссылке
  • Ресурсы доступны из кода и из XML

Как добавить ресурсы?

Как добавить ресурсы?

/assets vs /res

/assets

  • Можно работать как с директориями
  • Позволяет задать произвольные имена файлов ресурсов
  • Для чтения файлов нужно указывать относительный путь к файлу, начиная с /assets директории
  • Для чтения используется класс AssetManager
  • Файлы читаются, как поток байтов
  • От вызова к вызову будут читаться сырые данные, которые нужно парсить в runtime

/res

  • Ресурсы объединены по типу в специальных подкаталогах
  • Каждому ресурсу присваивается уникальный идентификатор
  • Идентификатор - статическая целочисленная переменная
  • Инструмент aapt создает класс R, содержащий идентификаторы всех ресурсов, во время компиляции
  • Ресурсы выбираются для текущей конфигурации
  • По идентификатору получаются готовые объекты

Ресурсы в приложении

aapt - Android Asset Packaging Tool - инструмент запаковки ресурсов

android.content.res.Resources - менеджер ресурсов, генерирует мапу ресурсов (файл c константами)

app.packagename.R.* - ключи ресурсов

Важно: позволяет с помощью аннотаций провалидировать ожидаемый ресурс на этапе компиляции

Типы ресурсов в структуре проекта

  • anim/
  • animator/
  • color/
  • drawable/
  • mipmap/
  • layout/
  • menu/
  • font/
  • raw/
  • xml/
  • values/attrs.xml
  • values/arrays.xml
  • values/colors.xml
  • values/dimens.xml
  • values/strings.xml
  • values/styles.xml
  • values/bools.xml
  • values/ids.xml
  • values/integers.xml

Как настраивать ресурсы под разную конфигурацию? Квалификаторы:

  • country code (MCC)
  • network code (MNC)
  • locale
  • layout direction
  • smallest screen width
  • screen width
  • screen height
  • size
  • ration
  • orientation
  • ui mode
  • night node
  • density
  • touch screen
  • keyboard
  • text input
  • navigation state
  • navigation method
  • version

Как настраивать ресурсы под разную конфигурацию? Квалификаторы:

  • country code (MCC)
  • network code (MNC)
  • locale
  • layout direction (ldrtl, ldltr)
  • smallest screen width
  • screen width (ex.: w720dp)
  • screen height (ex.: h720dp)
  • size
  • ration (long, notlong)
  • orientation (port, land)
  • ui mode
  • night node (night, notnight)
  • density
  • touch screen (notouch, finger)
  • keyboard (keysexposed, keyshidden, keyssoft)
  • text input (nokeys, qwerty, 12key)
  • navigation state (navexposed, navhidden)
  • navigation method (nonav, dpad, trackball, wheel)
  • version

Квалификаторы:

locale

  • fr (код языка)
  • en-rUS (код языка + код региона)

smallest screen width

  • sw320dp (смартфоны: 240x320 ldpi, 320x480 mdpi, 480x800 hdpi)
  • sw480dp (смартфоны, планшеты: 480x800 mdpi)
  • sw600dp (планшет 7'': 600x1024 mdpi)
  • sw720dp (планшет 10'': 720x1280 mdp)

version

  • v21
  • v23

density

  • ldpi ~ 120dpi - x0.75
  • mdpi ~ 160dpi - baseline x1
  • hdpi ~ 240dpi - x1.5
  • xhdpi ~ 320dpi - x2
  • xxdpi ~ 480dpi - x3
  • xxxdpi ~ 640dpi - x4
  • nodpi - no scaling
  • tvdpi ~ 231dpi

size

  • small (от 320x426 px)
  • normal (от 320x470 px)
  • large (от 480x640 px)
  • xlarge (от 720x960 px)

Device Configuration:


					Screen orientation: landscape
					Screen pixel density: hdpi
					Screen size: large
					Touchscreen type: finger
				

Resource folder:


					res/drawable
					res/drawable-notouch
					res/drawable-land
					res/drawable-land-ldpi
					res/drawable-land-finger
					res/drawable-hdpi
				
  • Убираем notouch
  • Пропускаем screen size
  • Убираем папки без "land"
  • Поиск по dpi
  • Поиск по touchscreen type

res/drawable-land-finger

Графика

Графика: растровая и векторная

Поддерживаемые форматы изображений

  • BMP - без сжатия
  • JPEG - сжатие с компрессией
  • PNG - сжатие без компрессии
  • GIF - с индексированным цветом
  • SVG - Scalable Vector Graphics

Bitmap

val bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888)

ALPHA_8

  • Хранит: прозрачность
  • Нет данных о цвете
  • 8 bits/px

RGB_565

  • Red & Blue - 5 bits (32)
  • Green - 6 bits (64)
  • Нет данных о прозрачности
  • 16 bits/px

ARGB_8888

  • ARGB - Alpha, Red,Green,Blue
  • 4 byte/px
  • ARGB_4444 - аналог ARGB_8888 (2 byte/px) - deprecated API >= 13

Сохранение и чтение Bitmap


                    val stream = FileOutputStream("image.jpg")
                    bitmap.compress(CompressFormat.JPEG, 50, stream)
                    stream.close()

                    BitmapFactory.decodeStream(
                        FileInputStream(file), // InputStream
                        null, // Rect - padding rect for bitmap
                        options // BitmapFactory.Options - downsampling
                    )
                

                    BitmapFactory.decodeResource(resources, R.drawable.ic_image)
                

                    BitmapFactory.decodeFile(imagePath, options)
                

Bitmap handling

  • Делаем recycle(), как только картинка становится не нужна.
  • Если нужно много изображений — выделяем память при старте приложения, создаём пул картинок.
  • При создании через BitmapFactory ставим нужные флаги в BitmapFactory.Options.
  • Проверяем размер картинки (BitmapOptions.inJustDecodeBounds).
  • Открываем картинку сразу с масштабированием.
  • Пробуем обрабатывать OutOfMemoryError и в случае нехватки памяти грузить картинку с другой цветовой палитрой или ещё уменьшить размер.

Canvas

Выполняет операции рисования

override fun onDraw(canvas: Canvas) // method of View's lifecycle, where we can draw on Canvas
  • drawARGB(), drawRGB(), drawColor() - заполнение цветом
  • drawPoint() - рисует точку
  • drawLine() - рисует линию
  • drawRect() - рисует прямоугольник
  • drawCircle() - рисует круг
  • drawOval() - рисует овал
  • drawArc() - рисует дугу
  • drawRoundRect() - рисует прямоугольник с закругленными краями
  • drawText() - рисует текст
  • drawBitmap() - рисует Bitmap
  • drawPaint() - закрашивает холст с заданной Paint
  • drawPath() - рисует контур

Трансформации Canvas

  • translate(dx: Float, dy: Float) - добавляет смещение для матрицы изображения
  • rotate(degrees: Float) - добавляет поворот в матрицу
  • rotate(degrees: Float, dx: Float, dy: Float) - поворот с заданной точкой поворота
  • scale(sx: Float, sy: Float) - масштабирует изображение
  • skew(sx: Float, sy: Float) - растягивает изображение
  • save() - сохранение текущей матрицы
  • restore() - удаляет все модификации после последнего вызова save()

Paint

Определяет с какими параметрами рисовать на Canvas

  • Цвет
  • Стиль: сплошная закраска и/или контурная
  • Толщина линий
  • Сглаживание на краях
  • Штрихпунктир
  • Параметры текста: размер, шрифт, стиль

Градиент: Shader

  • LinearGradient
  • RadialGradient
  • SweepGradient
  • ComposeGradient
  • BitmapGradient

Paint - PathEffect

Path

Замкнутый контур, соединенный линиями или кривыми

Методы относительного перемещения

  • rMoveTo(dx, dy)
  • rLineTo(dx, dy)
  • rQuadTo(dx1, dy1, dx2, dy2)
  • rCubicTo(dx1, dy1, dx2, dy2, dx3, dy3)

Drawable

Абстрактный класс для рисования

  • Изображение
  • Фигура
  • Градиент
  • Сплошной цвет
  • Композиция
  • ...
  • BitmapDrawable
  • ShapeDrawable
  • NinePatchDrawable
  • ColorDrawable
  • LayerDrawable
  • TransitionDrawable
  • AnimationDrawable
  • StateListDrawable
  • ...

BitmapDrawable

Обертка над Bitmap

XML


				<ImageView
				android:layout_width="wrap_content"
				android:layout_height="wrap_content"
				android:src="@drawable/ic_cool_icon">

				<ImageView
				android:layout_width="wrap_content"
				android:layout_height="wrap_content"
				android:background="@drawable/ic_cool_icon">
			

Code


				imageView.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_cool_icon)) // src
				imageView.setBackgroundResource(R.drawable.ic_cool_icon) // background
			

Color Drawable

XML


				<View
				android:layout_width="wrap_content"
				android:layout_height="wrap_content"
				android:background="@color/cool_color">
			

Code


				imageView.setImageDrawable(ColorDrawable(R.color.black))
			

State List Drawable

Drawable, который может меняться в зависимости от состояния View

XML


                <selector xmlns:android="http://schemas.android.com/apk/res/android">
                    <item android:state_enabled="false" android:drawable="@drawable/bttn_grey_disabled"/>
                    <item android:state_pressed="true" android:drawable="@drawable/bttn_orange_selected"/>
                    <item android:drawable="@drawable/bttn_orange_normal"/>
                </selector>
			

Code


                val stateListDrawable = StateListDrawable()

                stateListDrawable.addState(intArrayOf(android.R.attr.state_pressed), ContextCompat.getDrawable(context, R.drawable.bttn_orange_selected))
                stateListDrawable.addState(StateSet.WILD_CARD, ContextCompat.getDrawable(context, R.drawable.bttn_orange_normal))

                view.setBackground(stateListDrawable)
			

Shape Drawable

Drawable, который умеет рисовать примитивные фигуры

XML


                <shape xmlns:android="http://schemas.android.com/apk/res/android"
                    android:shape="oval">
                    <solid android:color="@color/fill_color">
                    <stroke
                        android:width="@dimen/stroke_width"
                        android:color="@color/border_color">
                </shape>
			

Code


                val shapeDrawable = ShapeDrawable(OvalShape())

                shapeDrawable.paint.strokeWidth = context.getResources().getDimension(R.dimen.stroke_width)
                shapeDrawable.paint.style = Paint.Style.FILL

                view.setBackground(shapeDrawable);
			

9-Patch Drawable

Drawable, который умеет растягиваться

Загрузка изображений: Glide

  • Простая в использовании
  • Из коробки поддерживает различные преобразования
  • Позволяет писать собственные преобразования

                    Glide
                        .with(context)
                        .load(url)
                        .placeholder(R.drawable.loading_spinner)
                        .into(imageView)
				

Glide.with(?)

Загрузка вместе с жизненным циклом Activity:

fun with(android.app.Activity activity): RequestManager

Загрузка вместе с жизненным циклом Fragment:

fun with(android.support.v4.app.Fragment fragment): RequestManager

Context - это контекст приложения:

fun with(android.content.Context context): RequestManager

Загрузка вместе с жизненным циклом Activity или Fragment, которые содержат View:

fun with(android.view.View view): RequestManager

Важно: запросы должны быть вызваны от контекста, на котором результат будет использоваться.

Glide Transformations

Built in types:

  • CenterCrop
  • FitCenter
  • CircleCrop

Using default transformations:


                    Glide
                        .with(fragment)
                        .load(url)
                        .fitCenter()
                        .into(imageView)
				

Using RequestOptions:


                    Glide
                        .with(context)
                        .load(url)
                        .apply(RequestOptions().centerCrop())
                        .into(imageView)
				

Using MultiTransformation:


                    Glide
                        .with(context)
                        .load(url)
                        .transform(MultiTransformation(FitCenter(), CustomTransformation()))
                        .into(imageView)
				

Дополнительные ссылки

Reveal.initialize({ center: true })