Ответ
Да, работал. Создавал кастомные View, переопределяя методы onDraw(), onMeasure(), onLayout(). Например, для анимированного прогресс-бара:
class CustomProgressBar @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : View(context, attrs) {
private var progress = 0f
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// Рисуем прогресс
canvas.drawRect(0f, 0f, width * progress, height.toFloat(), paint)
}
fun setProgress(progress: Float) {
this.progress = progress.coerceIn(0f, 1f)
invalidate()
}
}
Основные моменты:
- Обработка атрибутов из XML через
obtainStyledAttributes - Корректная работа с
onMeasureдля wrap_content - Оптимизация перерисовки через
clipRectилиsave/restore - Поддержка аппаратного ускорения
Ответ 18+ 🔞
А, ну это классика, ебать мои старые костыли! Да, работал, конечно. Это ж как в старые добрые времена — самому всё с нуля городить, когда стандартные виджеты не катят. Создавал кастомные View, переопределяя эти самые священные методы: onDraw(), onMeasure(), onLayout(). Чувствуешь себя богом интерфейса, пока не начнётся эта ёперная борьба с wrap_content.
Вот, смотри, элементарный пример — анимированный прогресс-бар. Проще пареной репы, но тут вся суть:
class CustomProgressBar @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : View(context, attrs) {
private var progress = 0f
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// Рисуем прогресс
canvas.drawRect(0f, 0f, width * progress, height.toFloat(), paint)
}
fun setProgress(progress: Float) {
this.progress = progress.coerceIn(0f, 1f)
invalidate()
}
}
С виду — хуй с горы, ан нет. А теперь лови основные грабли, на которых все пиздятся, пока не набьют шишку.
-
Атрибуты из XML. Это же святое! Без
obtainStyledAttributesтвой кастомный виджет — просто мартышлюшка, которую нельзя нормально настроить из разметки. Надо вытягивать цвета, толщины, флаги, а то потом будешь руками в коде всё пихать — терпения ноль ебать. -
Этот ёбаный
onMeasureдля wrap_content. Вот тут-то и начинается цирк. Если не обработать — твоя вьюха сожрёт весь экран, будто ей неймётся. Надо правильно посчитать свои хотелки, вызватьsetMeasuredDimension(), а иначе будет пиздопроебибна с версткой. -
Оптимизация перерисовки. Рисуешь всё подряд в
onDraw()? Ну и зря. Если виджет сложный, надо использоватьclipRect, чтобы лишние области не трогать, илиsave()/restore()для трансформаций канваса. Иначе на слабых устройствах будет не анимация, а слайд-шоу из адских мук. Сам от себя охуеешь, глядя на просадки фпс. -
Аппаратное ускорение. Его поддержка — это не просто галочка. Иногда некоторые операции рисования (особенно всякие тени или сложные пути) могут вести себя как хитрая жопа — то работают, то нет. Надо знать, что можно, а что нельзя при включённом слое.
Короче, дело это благородное, но чтобы не вышло манда с ушами, надо всё делать с умом. Зато когда работает как часы — чувствуешь себя королём.