Что такое view в android studio
Перейти к содержимому

Что такое view в android studio

  • автор:

View и

В разделе Widgets есть легковесный компонент View. У него нет текста, картинки и почти не потребляет ресурсов. Используется достаточно редко, но его удобно использовать как заглушку. Например, мы можем задать ему размер и фоновый цвет. Это гораздо удобнее, чем убирать текст у TextView, чтобы достичь такого же эффекта, так как TextView тянет за собой кучу методов и свойств.

В разделе Containers (в старых версиях студии Advanced) можно увидеть элемент для использования собственных компонентов.

Для начала вам следует создать собственный класс на основе View/ViewGroup или его предков. Затем, когда вы выберите элемент , то в диалоговом окне можете увидеть созданный класс или выбрать что-то другое.

Примеры собственных компонентов представлены ниже.

Урок 8. Как управлять View-элементами экрана из java кода (Android Studio)

Как вывести свой текст в TextView, изменить текст кнопки (Button) и программно установить флаг на чекбоксе (CheckBox)? В java для этого есть соответствующие методы. Но чтобы java методы могли как-то работать с View- элементами экрана android-приложения, например, менять текст в поле TextView, они должны эти самые элементы экрана как-то находить. Для этого нужно присвоить ID (идентификатор) тому View, с которым вы хотите взаимодействовать. В этом уроке мы научимся обращаться из кода к View-элементам на экране и менять их свойства.

#android #AndroidStudio #startandroid

Вам також може сподобатися

Now in Android

Уроки по android разработке на Java 0 1 900
Добро пожаловать в Now in Android, ваше текущее руководство по новинкам и важным событиям

Урок 11. Принципы навигации внутри и между андроид-приложениями

Архитектура андроид-приложений 0 10 232

Продолжая серию уроков о разработке мобильных приложений, мы будем изучать компонент Navigation набора инструментов

Broadcast Receivers

Документация по android 2 31 018

Перевод статьи на Медиуме о технологии Broadcast Receivers (широковещательные приемники). Это компоненты андроид, которые

Урок 17. Создание View-компонент в рабочем приложении

На прошлом уроке мы создавали компоненты в методе Activity.onCreate, т.е. при создании приложения. На этом уроке будем создавать уже в работающем приложении. Создавать будем Button-ы, т.к. они наглядней всего отображаются. Будем указывать текст, который будет отображен на кнопке и выравнивание: слева, по центру или справа. Также предусмотрим возможность удаления созданных элементов.

Project name: P0171_DynamicLayout2
Build Target: Android 2.3.3
Application name: DynamicLayout2
Package name: ru.startandroid.develop.dynamiclayout2
Create Activity: MainActivity

Создадим экран, который поможет нам создавать View-компоненты. Открываем main.xml и пишем там следующее:

Рассмотрим подробно экран.

rgGravity – это RadioGroup, с тремя RadioButton (rbLeft, rbCenter, rbRight). Этот компонент мы используем для выбора выравнивания создаваемого компонента
etName – текстовое поле, здесь будем указывать текст, который будет отображаться на созданном компоненте
btnCreate – кнопка, запускающая процесс создания.
btnClear – кнопка, стирающая все, что создали
llMain – вертикальный LinearLayout, в котором будут создаваться компоненты

Экран готов, давайте кодить реализацию. Открываем MainActivity.java. Начнем с того, что опишем и найдем все необходимые нам компоненты. Кстати, у нас есть пара кнопок, которые мы будем использовать, значит им нужен обработчик. В качестве обработчика назначим Activity (т.е. необходимо дописать: implements OnClickListener) и создадим пустой пока метод обработки onClick:

public class MainActivity extends Activity implements OnClickListener < LinearLayout llMain; RadioGroup rgGravity; EditText etName; Button btnCreate; Button btnClear; int wrapContent = LinearLayout.LayoutParams.WRAP_CONTENT; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.main); llMain = (LinearLayout) findViewById(R.id.llMain); rgGravity = (RadioGroup) findViewById(R.id.rgGravity); etName = (EditText) findViewById(R.id.etName); btnCreate = (Button) findViewById(R.id.btnCreate); btnCreate.setOnClickListener(this); btnClear = (Button) findViewById(R.id.btnClear); btnClear.setOnClickListener(this); >@Override public void onClick(View v) < // TODO Auto-generated method stub >>

Я также создал переменную wrapContent и буду хранить в ней значение LinearLayout.LayoutParams.WRAP_CONTENT. Делаю это только для снижения громоздкости кода.

Теперь опишем процесс создания Button-компонента заполнив метод onClick:

@Override public void onClick(View v) < switch (v.getId()) < case R.id.btnCreate: // Создание LayoutParams c шириной и высотой по содержимому LinearLayout.LayoutParams lParams = new LinearLayout.LayoutParams( wrapContent, wrapContent); // переменная для хранения значения выравнивания // по умолчанию пусть будет LEFT int btnGravity = Gravity.LEFT; // определяем, какой RadioButton "чекнут" и // соответственно заполняем btnGravity switch (rgGravity.getCheckedRadioButtonId()) < case R.id.rbLeft: btnGravity = Gravity.LEFT; break; case R.id.rbCenter: btnGravity = Gravity.CENTER_HORIZONTAL; break; case R.id.rbRight: btnGravity = Gravity.RIGHT; break; >// переносим полученное значение выравнивания в LayoutParams lParams.gravity = btnGravity; // создаем Button, пишем текст и добавляем в LinearLayout Button btnNew = new Button(this); btnNew.setText(etName.getText().toString()); llMain.addView(btnNew, lParams); break; > >

Разберем написанное. Для начала мы проверяем, что была нажата кнопка btnCreate – т.е. кнопка создания. Затем создаем LayoutParams с высотой и шириной по содержанию. Здесь я использовал переменную, про которую писал выше – wrapContent. Иначе получилось бы довольно громоздко.

Далее создаем переменную btnGravity, в которую по умолчанию запишем значение выравнивания LEFT. Для определения, какой RadioButton выделен в данный момент, используем метод getCheckedRadioButtonId – он для RadioGroup возвращает ID «чекнутого» RadioButton-а. Мы его сравниваем с нашими тремя ID и заносим соответствующее значение в переменную btnGravity. Скидываем это значение в gravity у LayoutParams.

Далее создаем кнопку и присваиваем ей текст из etName. Обратите внимание, что недостаточно написать getText, т.к. это не даст текста. Необходимо еще вызвать метод toString. Ну и в конце добавляем созданный Button в наш LinearLayout.

Сохраним все и запустим приложение. Добавим несколько кнопок.

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

Когда вводите текст, снизу появляется клавиатура и закрывает обзор. Чтобы она исчезла, надо нажать кнопку Back (Назад) на эмуляторе или ESC на обычной клавиатуре. Если клавиатура появляется японская с иероглифами, вызовите контекстное меню для поля ввода (долгое нажатие левой кнопкой мыши), нажмите Input method и выберите из списка Android Keyboard.

Осталось нереализованной кнопка Clear, которая призвана удалять все созданное. Для этого нам необходимо дополнить метод onClick, добавим в switch ( v.getId ()) еще один case:

case R.id.btnClear: llMain.removeAllViews(); Toast.makeText(this, "Удалено", Toast.LENGTH_SHORT).show(); break;

Метод removeAllViews удаляет все дочерние View-компоненты с нашего LinearLayout. С помощью Toast выводим на экран сообщение об успехе. Сохраним, запустим и проверим. Добавляем несколько кнопок, жмем кнопку Clear и наблюдаем результат:

В итоге у нас получилось очень даже динамическое приложение, которое умеет менять само себя.

На форуме задают вопрос: как потом получить доступ к этим созданным компонентам. Тут есть пара простых вариантов.

1) При создании вы можете сами присваивать компонентам ID. Это делается методом setId . И потом по этим ID просто вызываете findViewById.

2) Вы можете сохранять созданные компоненты в свой массив или список. Либо можете воспользоваться методом getChildAt. Вызов этого метода для llMain позволит получить его дочерние компоненты по индексу. Получить кол-во дочерних элементов позволит метод getChildCount.

Полный код урока:

public class MainActivity extends Activity implements OnClickListener < LinearLayout llMain; RadioGroup rgGravity; EditText etName; Button btnCreate; Button btnClear; int wrapContent = LinearLayout.LayoutParams.WRAP_CONTENT; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.main); llMain = (LinearLayout) findViewById(R.id.llMain); rgGravity = (RadioGroup) findViewById(R.id.rgGravity); etName = (EditText) findViewById(R.id.etName); btnCreate = (Button) findViewById(R.id.btnCreate); btnCreate.setOnClickListener(this); btnClear = (Button) findViewById(R.id.btnClear); btnClear.setOnClickListener(this); >@Override public void onClick(View v) < switch (v.getId()) < case R.id.btnCreate: // Создание LayoutParams c шириной и высотой по содержимому LinearLayout.LayoutParams lParams = new LinearLayout.LayoutParams( wrapContent, wrapContent); // переменная для хранения значения выравнивания // по умолчанию пусть будет LEFT int btnGravity = Gravity.LEFT; // определяем, какой RadioButton "чекнут" и // соответственно заполняем btnGravity switch (rgGravity.getCheckedRadioButtonId()) < case R.id.rbLeft: btnGravity = Gravity.LEFT; break; case R.id.rbCenter: btnGravity = Gravity.CENTER_HORIZONTAL; break; case R.id.rbRight: btnGravity = Gravity.RIGHT; break; >// переносим полученное значение выравнивания в LayoutParams lParams.gravity = btnGravity; // создаем Button, пишем текст и добавляем в LinearLayout Button btnNew = new Button(this); btnNew.setText(etName.getText().toString()); llMain.addView(btnNew, lParams); break; case R.id.btnClear: llMain.removeAllViews(); Toast.makeText(this, "Удалено", Toast.LENGTH_SHORT).show(); break; > > >

На следующем уроке:

— изменяем layout-параметры для уже существующих компонентов экрана

Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Compose, Kotlin, RxJava, Dagger, Тестирование, Performance

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

Custom View в Android — краткое руководство

Обзор возможностей кастомных View с примерами кода на Kotlin. В конце статьи вас ждет бонус в виде ссылок на полезные статьи и обучающие видео по данной теме.

Разработчик на Android создает сложный экран с использованием Custom View и в итоге решает уйти в iOS разработку

  1. Введение.
    — Когда может понадобиться реализация собственного View?
    — Способы создания Custom View.
    — Иерархия View в Android.
  2. Жизненный цикл View.
  3. Конструкторы View.
  4. Методы View.
    — onAttachToWindow()
    — onMeasure()
    — onLayout()
    — onDraw()
    — onSizeChanged()
    — onSaveInstanceState() и onRestoreInstanceState()
    — onTouchEvent()
  5. Обновление View.
    — invalidate()
    — requestLayout()
  6. Атрибуты для Custom View.
  7. Дополнительные материалы для изучения.

1. Введение

Обычно термин Custom View обозначает View , которого нет в sdk Android. Другими словами — это пользовательская реализация View , которая может содержать собственную логику и визуальный интерфейс.

Когда может понадобиться реализация собственного View?

— Специфичный дизайн или анимация
Если в стандартных View недостаточно функциональности, и нужно добавить новые возможности (график функции, сложная диаграмма).

— Специфичная обработка жестов
Свайп, тап, зум, поворот элемента по двойному касанию и другие комбинации жестов для взаимодействия с элементами интерфейса.

— Улучшение производительности
Например, для оптимизации отображения большого количества графических объектов (карта с большим количеством маркеров).

Способы создания Custom View.

— Расширение функциональности стандартного View или ViewGroup
Допустим, что нам не хватает стандартных возможностей Button . Мы создаём свой класс и наследуемся от класса android.widget.Button . Затем переопределяем методы для отображения и обработки событий. Этот подход используется для дополнения функциональности существующих элементов View или изменения их внешнего вида.

— Создание кастомного класса View с нуля
Этот способ подходит, если мы хотим создать свой собственный элемент View . Создаем класс, который наследуется от класса View , а затем переопределяем методы для отображения и обработки событий. Этот метод пригодится для создания сложных и уникальных пользовательских интерфейсов (кастомный прогресс-бар, графики или диаграммы).

— Использовать существующие библиотеки
Можно использовать существующие библиотеки, которые предоставляют набор готовых компонентов и методов для построения UI и могут быть настроены под ваш проект. Такой подход позволяет сэкономить время на разработку, но ограничивает вас возможностями библиотеки. Пример: MPAndroidChart для создания различных графиков и диаграмм.

Иерархия View в Android.

2. Жизненный цикл View

Полная версия жизненного цикла View :

При создании Custom View мы используем лишь методы с приставкой On , поэтому схему можно упростить:

3. Конструкторы View

Создание View начинается с конструктора с различными параметрами: Context , AttributeSet , defStyleAttr и defStyleRes . View имеет четыре конструктора, и вам нужно будет переопределить хотя бы один из них:

class TestView : View

В Kotlin можно использовать @JvmOverloads . Эта аннотация генерирует все возможные комбинации параметров конструктора, которые могут быть использованы при вызове из Java.

class TestView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0 ) : View(context, attrs, defStyleAttr) < // Your code here >
1. Конструктор с одним параметром — Context

Используется только в том случае, если View мы хотим создавать из кода, а не из XML.

2. Конструктор с двумя параметрами — Context и AttributeSet

Используется для создания View с использованием XML-макета. В этом конструкторе можно получить значения атрибутов View , указанных в XML-разметке, и использовать их для настройки свойств вашего Custom View .

3. Конструктор с тремя параметрами — Context, AttributeSet и defStyleAttr

Вызывается при создании View с помощью XML-разметки и задании значения стиля ( defStyleAttr ) из темы.

4. Конструктор с четырьмя параметрами — Context, AttributeSet, defStyleAttr и defStyleRes Также используется для создания View с использованием XML-макета, со стилем из темы и/или с ресурсом стиля.

4. Методы View

1. Метод onAttachToWindow()

После вызова данного метода, наша View прикрепляется к нашему Activity и знает о других элементах, которые также находятся на этом экране.

2. Метод onMeasure()

Конечная цель метода onMeasure() — определить размер и расположение вашего View на экране. В качестве параметров он принимает две переменные widthMeasureSpec и heightMeasureSpec , которые в свою очередь представляют собой требования измерения ширины и высоты вашего View . При переопределении данного метода, необходимо указать ширину и высоту вашего View самостоятельно, используя метод setMeasuredDimension() .

class CustomView(context: Context, attrs: AttributeSet) : View(context, attrs) < override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) < super.onMeasure(widthMeasureSpec, heightMeasureSpec) val width = MeasureSpec.getSize(widthMeasureSpec) val height = MeasureSpec.getSize(heightMeasureSpec) setMeasuredDimension(width, height) >>

MeasureSpec — это класс, используемый для определения размеров View в Android. Когда View помещается на экран, ей нужно знать, какое место ей предоставлено, чтобы правильно расположиться и отобразиться. MeasureSpec состоит из двух основных компонентов: размера и режима измерения.

Режим измерения может быть одним из трех типов:

  • EXACTLY (точно) — размер View должен быть задан точно (например, в dp или px). Это может быть указано в макете View с атрибутом android:layout_width или android:layout_height со значением фиксированной ширины или высоты.
  • AT_MOST (не больше) — View может быть любого размера, который не превышает указанный максимальный размер, например, layout_width=»wrap_content» . Это означает, что View может иметь любой размер, пока он не превышает размер родительского контейнера.
  • UNSPECIFIED (неопределенный) — размер View может быть любым, не ограниченным размером родителя.

Для каждого измерения View , то есть для ширины и высоты, используется отдельный MeasureSpec . Он передается в метод onMeasure() в качестве аргумента. Для того, чтобы получить размеры View на основе MeasureSpec , можно использовать методы MeasureSpec.getSize() и MeasureSpec.getMode() :

  • getSize(measureSpec: Int) — извлекает размер из заданного объекта MeasureSpec .
  • getMode(measureSpec: Int) — извлекает режим из заданного объекта MeasureSpec .

Пример использования MeasureSpec в методе onMeasure() :

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) < val desiredWidth = 100 // Предполагаемая ширина View val desiredHeight = 100 // Предполагаемая высота View val widthMode = MeasureSpec.getMode(widthMeasureSpec) val widthSize = MeasureSpec.getSize(widthMeasureSpec) val heightMode = MeasureSpec.getMode(heightMeasureSpec) val heightSize = MeasureSpec.getSize(heightMeasureSpec) val width = when (widthMode) < MeasureSpec.EXACTLY ->widthSize // Задан конкретный размер для ширины MeasureSpec.AT_MOST -> min(desiredWidth, widthSize) // Размер не должен превышать заданный размер else -> desiredWidth // Задать предпочтительный размер, если точного или максимального размера не задано > val height = when (heightMode) < MeasureSpec.EXACTLY ->heightSize // Задан конкретный размер для высоты MeasureSpec.AT_MOST -> min(desiredHeight, heightSize) // Размер не должен превышать заданный размер else -> desiredHeight // Задать предпочтительный размер, если точного или максимального размера не задано > setMeasuredDimension(width, height) // Устанавливаем фактический размер View >

3. Метод onLayout()

Метод onLayout() вызывается при каждом изменении размера и позиции View , в том числе при его создании и перерисовке. Обычно этот метод переопределяется в Custom View только в том случае, когда в нем есть дочерние View , которые нужно разместить в определенном порядке.

4. Метод onDraw()

Основной метод при разработке собственной View . При переопределении метода onDraw() используется объект Canvas (2D-холст), на котором можно рисовать графические элементы. Также в этом методе можно использовать объекты Paint и Path , которые определяют стиль и форму рисуемых элементов.

1. Canvas

Canvas предоставляет нам методы для рисования фигур, линий, текста и других элементов на экране, например:

  • drawColor(color: Int) — заливает всю область цветом, указанным в аргументе.
  • drawLine(startX: Float, startY: Float, stopX: Float, stopY: Float, paint: Paint) — рисует линию, заданную двумя точками.
  • drawRect(left: Float, top: Float, right: Float, bottom: Float, paint: Paint) — рисует прямоугольник, заданный координатами левого верхнего и правого нижнего углов.
  • drawCircle(cx: Float, cy: Float, radius: Float, paint: Paint) — рисует круг, заданный координатами центра и радиусом.
  • drawText(text: String, x: Float, y: Float, paint: Paint) — рисует текст, заданный строкой и координатами базовой точки.
2. Paint

Объект Paint представляет собой кисть, с помощью которой мы рисуем на Canvas .
Примеры методов для val paint = Paint() :

  • color (цвет рисования) — paint.color = Color.RED
  • strokeWidth (ширина линии рисования) — paint.strokeWidth = 10f
  • style (стиль рисования) — paint.style = Paint.Style.FILL . Принимает в качестве параметра одно из значений класса Paint.Style : FILL , STROKE или FILL_AND_STROKE .
  • textSize (размер шрифта текста) — paint.textSize = 30f

Пример использования Paint и Canvas :

class MyCustomView(context: Context, attrs: AttributeSet?) : View(context, attrs) < private val paint = Paint() override fun onDraw(canvas: Canvas) < super.onDraw(canvas) // Устанавливаем цвет и стиль для Paint paint.color = Color.RED paint.style = Paint.Style.FILL // Рисуем круг на Canvas canvas.drawCircle(width / 2f, height / 2f, 100f, paint) // Устанавливаем цвет и стиль для Paint paint.color = Color.BLUE paint.style = Paint.Style.STROKE paint.strokeWidth = 10f // Рисуем прямоугольник на Canvas canvas.drawRect(50f, 50f, 200f, 200f, paint) >>

Создание объектов в onDraw() может привести к лишним затратам памяти и ухудшению производительности приложения. Метод onDraw() вызывается при каждой перерисовке View , поэтому слишком частое создание новых объектов Paint может вызвать нагрузку на сборщик мусора. Вместо этого рекомендуется создать объект Paint в конструкторе класса или в другом подходящем методе и переиспользовать его в методе onDraw() .

Таким образом, вместо создания новых объектов Paint в методе onDraw() , лучше создать их в конструкторе класса, например:

class MyCustomView(context: Context, attrs: AttributeSet?) : View(context, attrs) < private val fillPaint = Paint().apply < color = Color.RED style = Paint.Style.FILL >private val strokePaint = Paint().apply < color = Color.BLUE style = Paint.Style.STROKE strokeWidth = 10f >override fun onDraw(canvas: Canvas) < super.onDraw(canvas) // Рисуем круг на Canvas canvas.drawCircle(width / 2f, height / 2f, 100f, fillPaint) // Рисуем прямоугольник на Canvas canvas.drawRect(50f, 50f, 200f, 200f, strokePaint) >>

В этом примере мы создаем два объекта Paint в конструкторе класса и настраиваем их свойства один раз. Затем мы используем эти объекты Paint в методе onDraw() для рисования круга и прямоугольника на Canvas . Таким образом, мы избегаем создания новых объектов Paint при каждой перерисовке View и уменьшаем нагрузку на сборщик мусора.

Далее еще несколько полезных методов, которые вы будете применять при разработке собственного View .

5. Метод onSizeChanged()

Метод onSizeChanged() вызывается при изменении размеров View (смена ориентация устройства, изменение размера родительского контейнера) и может быть переопределен в кастомном View для реакции на эти изменения. Метод имеет следующую сигнатуру:

override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) < super.onSizeChanged(w, h, oldw, oldh) // Your code here >
  • w — новая ширина View
  • h — новая высота View
  • oldw — старая ширина View
  • oldh — старая высота View

В onSizeChanged() мы как раз выполняем нужные расчеты, подготавливаем данные для дальнейшей отрисовки в методе onDraw() . В идеале, мы не ведем никакие расчеты в onDraw() , а берем конкретные подготовленные цифры и просто рисуем.

class TestView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrs, defStyleAttr) < private val circlePaint = Paint().apply < color = Color.RED style = Paint.Style.FILL >private val rectPaint = Paint().apply < color = Color.BLUE >private val arcPaint = Paint().apply < color = Color.GREEN >private val rectF = RectF() private val arcRectF = RectF() private var centerX = 0f private var centerY = 0f override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) < super.onSizeChanged(w, h, oldw, oldh) rectF.left = 20f rectF.top = 40f rectF.right = w - 20f rectF.bottom = h - 40f arcRectF.left = 20f arcRectF.top = 40f arcRectF.right = w - 20f arcRectF.bottom = h - 40f centerX = w / 2f centerY = h / 2f >override fun onDraw(canvas: Canvas) < super.onDraw(canvas) canvas.drawRect(rectF, rectPaint) canvas.drawCircle(centerX, centerY, 100f, circlePaint) canvas.drawArc(arcRectF, 180f, 90f, true, arcPaint) >>

6. Методы onSaveInstanceState() и onRestoreInstanceState()

Методы onSaveInstanceState() и onRestoreInstanceState() позволяют сохранять и восстанавливать состояние View в случае, когда система уничтожает и пересоздает View , например, при повороте экрана или при нехватке памяти.

Метод onSaveInstanceState() вызывается перед уничтожением View , и в нем необходимо сохранить состояние. В этом методе можно поместить все нужные нам данные в Bundle с помощью метода put. () , например:

override fun onSaveInstanceState(): Parcelable

Здесь мы сохраняем текст, отображаемый в textView в Bundle , который затем возвращается в качестве результата. Также мы вызываем super.onSaveInstanceState() и передаем его результат в Bundle с помощью метода putParcelable() , чтобы сохранить состояние базового класса.

Метод onRestoreInstanceState() вызывается после того, как View была пересоздана, чтобы восстановить ее состояние из Bundle . В этом методе можно извлечь необходимые данные из Bundle с помощью метода get. () , например:

override fun onRestoreInstanceState(state: Parcelable?)

Здесь мы восстанавливаем текст в textView из Bundle , который был передан в качестве параметра. Также мы вызываем метод super.onRestoreInstanceState() и передаем ему сохраненное состояние базового класса с помощью метода getParcelable() .

Метод onRestoreInstanceState() может вызываться после метода onFinishInflate() , поэтому необходимо учитывать это при восстановлении состояния View .

Также стоит отметить, что эти методы могут работать только с Serializable или Parcelable типами данных. Если вам нужно сохранить другой тип данных, например, объект вашего собственного класса, то вам необходимо реализовать его сериализацию и десериализацию в методах onSaveInstanceState() и onRestoreInstanceState() соответственно.

7. Метод onTouchEvent()

Метод onTouchEvent() — это один из методов обработки событий пользовательского ввода в View . Вызывается при каждом событии касания на View , например при нажатии, перемещении или отпускании пальца.

Метод возвращает значение типа Boolean , которое указывает, было ли событие обработано этим методом. Если метод возвращает true , это означает, что событие было обработано и больше никаких действий не требуется, если он возвращает false , событие продолжит свой путь по иерархии View и будет обработано другими методами.

Пример использования onTouchEvent() в кастомной View :

class MyCustomView(context: Context, attrs: AttributeSet) : View(context, attrs) < override fun onTouchEvent(event: MotionEvent): Boolean < when (event.action) < MotionEvent.ACTION_DOWN -> < // обработка нажатия пальца на экран return true >MotionEvent.ACTION_MOVE -> < // обработка перемещения пальца по экрану return true >MotionEvent.ACTION_UP -> < // обработка отпускания пальца от экрана return true >> return super.onTouchEvent(event) > >

В этом примере мы переопределяем метод onTouchEvent() и используем его для обработки трех основных событий касания на экране:

ACTION_DOWN — когда палец нажимается на экран
ACTION_MOVE — когда палец перемещается по экрану
ACTION_UP — когда палец отпускается от экрана.

Внутри каждого из этих блоков мы можем написать нужный нам код для обработки события, например, изменения цвета или размера View , а также возвращаем true , чтобы указать, что событие было обработано и больше никаких действий не требуется. Если событие не было обработано внутри блоков when , мы вызываем метод super.onTouchEvent(event) , чтобы передать событие на обработку другим методам в иерархии View .

5. Обновление View

Когда данные, используемые внутри View , изменяются, требуется обновить View , чтобы отобразить новые значения. Из диаграммы жизненного цикла видно, что существуют два метода, которые заставляют View перерисовываться:

  • invalidate() — используется, когда нужно только перерисовать ваш элемент.
  • requestLayout() — используется, когда нужно изменить размеры вашего View .
1. Метод invalidate()

Для обновления визуальной части нашего View , используется метод invalidate() . Например, когда ваш View-компонент обновляет свой текст, цвет или обрабатывает прикосновение. Это значит, что View-компонент будет вызывать только метод onDraw() , чтобы обновить своё состояние.

class CustomView(context: Context, attrs: AttributeSet?) : View(context, attrs) < private val paint = Paint() init < paint.color = Color.RED >override fun onDraw(canvas: Canvas) < canvas.drawCircle(width / 2f, height / 2f, width / 4f, paint) >fun changePaintColor(newColor: Int) < paint.color = newColor invalidate() // вызываем invalidate() для перерисовки Custom View >>
2. Метод requestLayout()

Если у нашего View были изменены размеры и/или позиция, необходимо вызвать метод requestLayout() , после которого последует вызов методов согласно жизненному циклу View , т.е. onMeasure() → onLayout() → onDraw() .

class CustomView(context: Context, attrs: AttributeSet?) : View(context, attrs) < private var myWidth = 0 private var myHeight = 0 override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) < myWidth = MeasureSpec.getSize(widthMeasureSpec) myHeight = MeasureSpec.getSize(heightMeasureSpec) setMeasuredDimension(myWidth, myHeight) >override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) < // располагаем элементы внутри Custom View >fun changeViewSize(newWidth: Int, newHeight: Int) < layoutParams.width = newWidth layoutParams.height = newHeight requestLayout() // вызываем requestLayout() для перерасположения Custom View >>

Особенность применения этих методов заключаются в том, что частая перерисовка или пересчет размеров View может замедлить работу приложения. Поэтому лучше использовать эти методы только в случае необходимости. Например, если изменения внешнего вида View могут быть объединены в один вызов invalidate() , то лучше объединить их для уменьшения количества перерисовок.

6. Атрибуты для Custom View

1. Определяем атрибуты, которые будут доступны для этого View .

Для этого нужно создать XML-файл в папке res/values с расширением attrs.xml и описать там нужные атрибуты.

2. В конструкторе View получаем атрибуты, переданные в XML, и сохраняем их в переменных класса.

class CustomView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrs, defStyleAttr) < private var customText: String? = null private var customTextColor: Int = Color.BLACK init < val typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomView, defStyleAttr, 0) customText = typedArray.getString(R.styleable.CustomView_customText) customTextColor = typedArray.getColor(R.styleable.CustomView_customTextColor, Color.BLACK) typedArray.recycle() >// остальной код >

Здесь мы получаем массив атрибутов typedArray из контекста с помощью метода context.obtainStyledAttributes() , передавая ему параметры attrs и стиль R.styleable.CustomView . Затем мы извлекаем значение атрибута customTextColor из массива typedArray с помощью метода typedArray.getColor() . Вторым параметром мы передаем значение по умолчанию, которое будет использоваться, если атрибут не был задан. После извлечения значения мы обязательно вызываем метод typedArray.recycle() , чтобы освободить ресурсы.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *